web-dev-qa-db-fra.com

Top 5 des requêtes SQL chronophages dans Oracle

Comment puis-je trouver des requêtes SQL peu performantes dans Oracle?

Oracle maintient des statistiques sur la zone SQL partagée et contient une ligne par chaîne SQL (v $ sqlarea). Mais comment identifier lequel d'entre eux est mal performant?

35
Kamal Joshi

J'ai trouvé que cette instruction SQL était un endroit utile pour commencer (désolé, je ne peux pas attribuer cela à l'auteur d'origine; je l'ai trouvé quelque part sur Internet):

SELECT * FROM
(SELECT
    sql_fulltext,
    sql_id,
    elapsed_time,
    child_number,
    disk_reads,
    executions,
    first_load_time,
    last_load_time
FROM    v$sql
ORDER BY elapsed_time DESC)
WHERE ROWNUM < 10
/

Cela trouve les principales instructions SQL qui sont actuellement stockées dans le cache SQL triées par temps écoulé. Les instructions disparaîtront du cache au fil du temps, il peut donc être inutile d'essayer de diagnostiquer le travail par lots de la nuit dernière lorsque vous vous mettez au travail à midi.

Vous pouvez également essayer de classer par disk_reads et exécutions. Les exécutions sont utiles car certaines applications pauvres envoient trop souvent la même instruction SQL. Ce SQL suppose que vous utilisez correctement les variables de liaison.

Ensuite, vous pouvez prendre le sql_id et child_number d'une déclaration et les nourrir dans ce bébé: -

SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id', &child));

Cela montre le plan réel du cache SQL et le texte intégral du SQL.

50
WW.

Vous pouvez trouver des analyses de table complètes gourmandes en disque avec quelque chose comme ceci:

SELECT Disk_Reads DiskReads, Executions, SQL_ID, SQL_Text SQLText, 
   SQL_FullText SQLFullText 
FROM
(
   SELECT Disk_Reads, Executions, SQL_ID, LTRIM(SQL_Text) SQL_Text, 
      SQL_FullText, Operation, Options, 
      Row_Number() OVER 
         (Partition By sql_text ORDER BY Disk_Reads * Executions DESC) 
         KeepHighSQL
   FROM
   (
       SELECT Avg(Disk_Reads) OVER (Partition By sql_text) Disk_Reads, 
          Max(Executions) OVER (Partition By sql_text) Executions, 
          t.SQL_ID, sql_text, sql_fulltext, p.operation,p.options
       FROM v$sql t, v$sql_plan p
       WHERE t.hash_value=p.hash_value AND p.operation='TABLE ACCESS' 
       AND p.options='FULL' AND p.object_owner NOT IN ('SYS','SYSTEM')
       AND t.Executions > 1
   ) 
   ORDER BY DISK_READS * EXECUTIONS DESC
)
WHERE KeepHighSQL = 1
AND rownum <=5;
17
Leigh Riffel

Vous pouvez prendre le tampon moyen obtenu par exécution pendant une période d'activité de l'instance:

SELECT username,
       buffer_gets,
       disk_reads,
       executions,
       buffer_get_per_exec,
       parse_calls,
       sorts,
       rows_processed,
       hit_ratio,
       module,
       sql_text
       -- elapsed_time, cpu_time, user_io_wait_time, ,
  FROM (SELECT sql_text,
               b.username,
               a.disk_reads,
               a.buffer_gets,
               trunc(a.buffer_gets / a.executions) buffer_get_per_exec,
               a.parse_calls,
               a.sorts,
               a.executions,
               a.rows_processed,
               100 - ROUND (100 * a.disk_reads / a.buffer_gets, 2) hit_ratio,
               module
               -- cpu_time, elapsed_time, user_io_wait_time
          FROM v$sqlarea a, dba_users b
         WHERE a.parsing_user_id = b.user_id
           AND b.username NOT IN ('SYS', 'SYSTEM', 'RMAN','SYSMAN')
           AND a.buffer_gets > 10000
         ORDER BY buffer_get_per_exec DESC)
 WHERE ROWNUM <= 20
5
Guille

Cela dépend de la version d'Oracle que vous avez, pour 9i et moins Statspack est ce que vous recherchez, 10g et plus, vous voulez awr , ces deux outils vous donneront le top sql et beaucoup d'autres choses.

2
Matthew Watson

l'information complète que j'ai obtenue de askTom-Oracle. J'espère que ça t'aide

select * 
from v$sql 
where buffer_gets > 1000000 
or disk_reads > 100000 
or executions > 50000 
2
Ras Rass

La requête suivante renvoie des instructions SQL qui effectuent un grand nombre de lectures de disque (inclut également l'utilisateur incriminé et le nombre d'exécutions de la requête):

SELECT t2.username, t1.disk_reads, t1.executions,
    t1.disk_reads / DECODE(t1.executions, 0, 1, t1.executions) as exec_ratio,
    t1.command_type, t1.sql_text
  FROM v$sqlarea t1, dba_users t2
  WHERE t1.parsing_user_id = t2.user_id
    AND t1.disk_reads > 100000
  ORDER BY t1.disk_reads DESC

Exécutez la requête en tant que SYS et ajustez le nombre de lectures de disque en fonction de ce que vous jugez excessif (100 000 fonctionne pour moi).

J'ai utilisé cette requête très récemment pour retrouver les utilisateurs qui refusent de profiter de Explain Plans avant d'exécuter leurs instructions.

J'ai trouvé cette requête dans un vieux livre de réglage Oracle SQL (que je n'ai malheureusement plus), donc excuses, mais pas d'attribution.

2
Steven Wolfe

Il existe plusieurs façons de procéder, mais utilisez un google pour tkprof

Il n'y a pas d'interface graphique ... c'est entièrement en ligne de commande et peut-être une touche intimidante pour les débutants Oracle; mais c'est très puissant.

Ce lien ressemble à un bon début:

http://www.oracleutilities.com/OSUtil/tkprof.html

1
cagcowboy