Logo Oracle Deutschland   DBA Community  -  Juli 2008 (ergänzt Dezember 2012)
SQL Tuning Sets im Einsatz
von Ulrike Schwinn, Oracle Deutschland B.V. & Co. KG

Seit Oracle Database 10g mit der Einführung des Tuning Advisory Frameworks spielen die sogenannten SQL Tuning Sets (auch kurz STS) eine wichtige Rolle. Ein STS besteht dabei nicht alleine aus einer Ansammlung von gespeicherten SQL Texten. Zusätzlich werden z.B. Execution Kontext und Execution Statistiken im Data Dictionary mitabgespeichert.
Ein SQL Tuning Set besteht somit aus folgenden Komponenten:

  • Ein oder mehrere SQL Statements
  • Execution Kontext wie Bind Variablen, Parsing Schema usw.
  • Grundlegende Execution Statistiken wie Elapsed Zeit, CPU Zeit usw.
  • Ausführungspläne und Rowsource-Statistiken (optional)


  • Dabei kann ein STS aus verschiedensten Quellen geladen werden wie z.B. AWR, Cursor Cache (auch inkrementell) oder User definierten Statements. Um möglichst viele Statements im STS zu speichern, eignet sich die Anwendung des Cursor Cache. Sollen nur die Top Statements berücksichtigt werden, kann man sich auf die AWR Methode beschränken.

    Folgende Liste illustriert die möglichen Einsatzszenarien:
  • Speichermöglichkeiten für wiederkehrende Tuningaufgaben
  • Diagnose auf einem Remote System durch Transfermöglichkeiten
  • Ranking der Statements nach entsprechenden Statistiken
  • Grundlage für SQL Tuning Advisor und SQL Access Advisor
  • Basis der SQL Performance Analyse (durch den SQL Performance Analyzer) einsetzbar sogar ab Oracle Database 9i


  • STS sind verfügbar mit dem Oracle Tuning Pack und entweder graphisch über die Enterprise Manager Console oder im Linemode über das Package DBMS_SQLTUNE nutzbar.

    Erzeugen eines SQL Tuning Sets

    Wie eingangs schon erwähnt wurde, können SQL Tuning Sets aus unterschiedlichsten Quellen wie z.B. dem Cursor Cache erzeugt werden. Da die STS zusätzlich Basisstatistiken enthalten, sind diese als mögliche einschränkende Kriterien zugelassen. Die Basisstatistiken, die verwendet werden können sind dabei durch den Objekttyp SQLSET_ROW definiert. Informationen dazu findet man im PL/SQL Packages und Types References Handbuch.
    Beispiele für mögliche Statistiken sind:

  • SQL_TEXT für den SQL Text
  • PARSING_SCHEMA_NAME für das User Schema
  • MODULE bei Verwendung von DBMS_APPLICATION_INFO
  • ACTION bei Verwendung von DBMS_APPLICATION_INFO
  • ELAPSED_TIME
  • CPU_TIME
  • BUFFER_GETS
  • DISK_READS
  • ROWS_PROCESS
  • EXECUTIONS


  • Im folgenden Beispiel werden die Top 10 Statements aus dem aktuellen Cursor Cache selektiert und als Filterkriterien das Userschema "SCOTT" und eine bestimmte ELAPSED Zeit-Untergrenze (größer als 12 Sekunden) verwendet.
    EXECUTE DBMS_SQLTUNE.CREATE_SQLSET('SQLSET_1');
    DECLARE
     cur DBMS_SQLTUNE.SQLSET_CURSOR;
    BEGIN
     OPEN cur FOR
       SELECT VALUE(P)
       FROM table(DBMS_SQLTUNE.SELECT_CURSOR_CACHE(
       'parsing_schema_name = ''SCOTT'' AND elapsed_time >12000000', null, null, 
       null, null, 1, 10, null)) P;
       DBMS_SQLTUNE.LOAD_SQLSET(sqlset_name => 'SQLSET_1', populate_cursor => cur);
      CLOSE cur;
    END;
    /
    
    Weitere mögliche Filter Kriterien wie CPU_TIME, BUFFER_GETS usw. findet man im PL/SQL Handbuch . So können SQL Tuning Sets erzeugt werden, die bestimmten Performance- oder Umgebungs-Anforderungen wie z.B. Modulenangabe durch DBMS_APPLICATION_INFO genügen. Das folgende Beispiel demonstriert die Verwendung, dabei ist vorab der ACTION_NAME "TEST_BEREICH" in der Applikation verwendet worden. Ein Blick in die View V$SESSION gibt einen guten Überblick über die bereits existierende ACTION und MODUL Verwendung.
    EXECUTE DBMS_SQLTUNE.CREATE_SQLSET('SQLSET_2');
    DECLARE
      cur sys_refcursor;
    BEGIN OPEN cur FOR
    SELECT VALUE(P) 
        FROM table(
          DBMS_SQLTUNE.SELECT_CURSOR_CACHE('action = ''TEST_BEREICH''')) P;
    DBMS_SQLTUNE.LOAD_SQLSET(sqlset_name => 'SQLSET_2', populate_cursor => cur);
    END;
    /
    
    Möchte man Statements inkrementell über eine bestimmte Zeit aus dem Cursor Cache in einem SQL Tuning Set ansammeln, ist dies entweder mit dem Enterprise Manager oder mit der Prozedur CAPTURE_CURSOR_CACHE_SQLSET möglich. Das folgende Beispiel pollt über einen Zeitraum von 30 Minuten (1800 Sekunden) alle 5 Minuten die Statements aus dem Cursor Cache. Dabei dauert die Ausführung der Prozedur so lange wie der gegebene Zeitraum vorgibt - in unserem Fall 30 Minuten.
    EXECUTE DBMS_SQLTUNE.CREATE_SQLSET('SQL_WORKLOAD1');
    EXECUTE DBMS_SQLTUNE.CAPTURE_CURSOR_CACHE_SQLSET(
                    sqlset_name     => 'SQL_WORKLOAD,
                    time_limit      => 1800, 
                    repeat_interval => 300, 
                    basic_filter    => 'parsing_schema_name = ''SCOTT'' AND elapsed_time>12000000'); 
    

    Um das Sammeln von Statements abzubrechen, eignet sich das Anlegen eines Scheduler Jobs. Folgendes Beispiel zeigt eine Implementierung.
    BEGIN 
     DBMS_SQLTUNE.CREATE_SQLSET(
                sqlset_name  =>'&sts_name',
                sqlset_owner =>'&sts_owner');
    END;                                                      
    /  
    BEGIN 
     DBMS_SCHEDULER.CREATE_JOB(
        job_name   => 'LOAD_STS',
        job_type   => 'PLSQL_BLOCK',
        job_action =>
          'BEGIN dbms_sqltune.capture_cursor_cache_sqlset(
                 sqlset_name     => ''&sts_name'',
                 time_limit      => 25200,
                 repeat_interval => 900,
                 sqlset_owner    => ''&sts_owner'',
                 basic_filter => ''parsing_schema_name NOT IN ''''DBSNMP'''',''''SYS'''')'');
            END;',
        enabled  => TRUE);
    END;
    / 
    -- Job Abbruch mit 
    BEGIN
      DBMS_SCHEDULER.STOP_JOB(job_name => 'LOAD_STS');
    END;
    /
    
    Der folgende Screenshot zeigt die Implementierung dieser Funktionalität im Enterprise Manager:


    Möchte man einen Überblick über alle STS erhalten eignet sich folgende Abfrage.
    SQL> SELECT name, statement_count FROM dba_sqlset ORDER BY created;
    
    NAME                           STATEMENT_COUNT
    ------------------------------ ---------------
    rat1_c_245324                              586
    rat1_c_2453241375555946                    586
    REPLAY_orcl_20101011_r_2236708             457
    REPLAY_test_r_4692651                      355
    REPLAY_orcl_20101011_r_6480785             676
    ...
    
    Auskunft über den genauen Inhalt der SQL Tuning Sets erhält man dann über die Data Dictionary View DBA_SQLSET_STATEMENTS oder die entsprechende Enterprise Manager Seite.
    SQL> SELECT sql_text,cpu_time,elapsed_time, executions, buffer_gets 
         FROM dba_sqlset_statements 
         WHERE sqlset_name='SQL_WORKLOAD3';
    
    SQL_TEXT
    --------------------------------------------------------------------------------
      CPU_TIME ELAPSED_TIME EXECUTIONS BUFFER_GETS
    ---------- ------------ ---------- -----------
    BEGIN DBMS_OUTPUT.DISABLE; END;
          8218       144234          1          75
    
    select count(*) from zn.zndb_10p
       1112864     34363168          1       65260
    
    select count(*), last_name from hr.bigemp where last_name like 'M%' group by las
         57724        57724          1         217
    
    select count(*) from hr.bigemp where last_name='King'
          7091        69174          2          99
    
    BEGIN :last :='King'; END;
    
          1567         1567          1           0
    
    select count(*) from hr.bigemp where last_name like 'M%'
        183577       210873          6        1296
     
    Der folgende Screenshot zeigt die Sichtweise im Enterprise Manager:

    Transfer von SQL Tuning Sets

    Abgesehen von Standardeigenschaften wie das Löschen oder das nachträgliche Ändern, gibt es auch die Möglichkeit, SQL Tuning Sets in andere Datenbanken zu transportieren. Dies ist besonders dann sinnvoll, wenn z.B. der Tuning Prozess ausgelagert werden soll. Folgender Ablauf beschreibt das Vorgehen:

  • Anlegen einer Staging Tabelle
  • EXECUTE DBMS_SQLTUNE.CREATE_STGTAB_SQLSET(table_name => 'STAGING_TABLE');   
    
  • Laden der Staging Tabelle mit Informationen aus einem oder mehreren SQL Tuning Sets
  • EXECUTE DBMS_SQLTUNE.PACK_STGTAB_SQLSET(sqlset_name        => 'SQL_WORKLOAD3',
    			                staging_table_name => 'STAGING_TABLE');
    
  • Exportieren und Importieren der Staging Tabelle in die entsprechende Umgebung. (Hinweis: Die Nutzung von Datapump sollte dabei allerdings nicht als SYSDBA erfolgen.)

  • Und zum Abschluss erfolgt das Entpacken der SQL Tuning Sets aus der Staging Tabelle mit folgendem Befehl:
  • EXECUTE DBMS_SQLTUNE.UNPACK_STGTAB_SQLSET(sqlset_name        => '%',
          					  replace            => TRUE,
          			                  staging_table_name => 'STAGING_TABLE'); 
    
    Eine graphische Unterstützung für den Transfer der SQL Tuning Sets findet man im Enterprise Manager.
    Nun kann das SQL Tuning Set bzw. die SQL Tunings Sets in der neuen Umgebung, die z.B. als Testumgebung dient, zum Einsatz kommen. Sogar die Releasestände der Umgebungen können dabei unterschiedlich sein. So kann ein SQL Tuning Set aus einer 10.1 in eine 10.2 oder gar in eine 11.1 Umgebung exportiert bzw. importiert werden, um das Verhalten in der neuen Umgebung zu testen.



    Weitere Anwendungen und Tipps

    Mit dem in Oracle Database 11g eingeführten SQL Performance Analyzer können auf diese Art und Weise, Performancevergleiche zwischen unterschiedlichen Releaseständen durchgeführt werden. Die 11g Datenbank kann dabei als Zielrelease genutzt werden oder zu Repository-Zwecke, um z.B. Vergleiche zwischen älteren Releaseständen z.B. 9i und 10g durchzuführen. Da in 9i noch keine SQL Tuning Sets zur Verfügung stehen, ist das SQL Performance Analyzer Interface so erweitert worden, dass Trace Files aus der Oracle 9i Datenbank, zu SQL Tuning Sets konvertiert werden können.

    STS können auch parallel während eines DB Replay Captures generiert werden (siehe auch DBMS_WORKLOAD_CAPTURE Package). Vorzuziehen ist allerdings die manelle Methode, da man hier nach Belieben Filter setzen kann.

    Ist das STS zu umfangreich, kann man man im Nachhinein das STS verkleinern - entweder über die graphische Oberfläche oder mithilfe des Package DBMS_SQLTUNE.

    EXECUTE DBMS_SQLTUNE.CREATE_SQLSET('SUBSET1');
    
    DECLARE
      cur sys_refcursor;
    BEGIN
      OPEN cur FOR
        SELECT VALUE (P) 
        FROM table(DBMS_SQLTUNE.SELECT_SQLSET(
             sqlset_name =>'REPLAY_us_r_44488776', 
             basic_filter=>'elapsed_time > 5000000')) P;
     
    DBMS_SQLTUNE.LOAD_SQLSET(sqlset_name => 'SUBSET1',
                            populate_cursor => cur); 
      CLOSE cur;
    END;
    /
    
    Noch kurz zum Thema Overhead: Das Generieren von STS erzeugt nur einen geringen Overhead, der vernachlässigbar ist und somit nicht ins Gewicht fallen sollte. Bei umfangreichen STS kann es allerdings zu einem Wachstum des SYSAUX Tablespces kommen. Man sollte daher das Wachstum dieses Tablespaces im Auge behalten.

    Im Anschluss noch ein paar Links zm Thema ...
    Mehr zu diesen und weiteren Themen rund um die Datenbank in einer der folgenden Tipps...

    Zurück zur Community-Seite