Топ 5 трудоемких SQL-запросов в Oracle - PullRequest
32 голосов
/ 25 ноября 2008

Как найти неэффективные SQL-запросы в Oracle?

Oracle поддерживает статистику по общей области SQL и содержит одну строку на строку SQL (v $ sqlarea). Но как мы можем определить, кто из них плохо работает?

Ответы [ 8 ]

46 голосов
/ 25 ноября 2008

Я нашел этот оператор SQL полезным для начала (извините, я не могу отнести его к первоначальному автору; я нашел его где-то в Интернете):

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
/

Здесь находятся основные операторы SQL, которые в настоящее время хранятся в кэше SQL, упорядоченные по истечении времени. С течением времени выписки из кэша исчезают, поэтому, возможно, не стоит пытаться диагностировать пакетное задание прошлой ночью, когда вы приступаете к работе в полдень.

Вы также можете попробовать упорядочить по disk_reads и выполнению. Выполнения полезны, потому что некоторые плохие приложения отправляют один и тот же оператор SQL слишком много раз. Этот SQL предполагает, что вы используете переменные связывания правильно.

Затем вы можете взять sql_id и child_number заявления и скормить их этому ребенку: -

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

Показывает фактический план из кэша SQL и полный текст SQL.

16 голосов
/ 06 декабря 2008

Вы можете найти интенсивное сканирование таблиц с интенсивным диском примерно так:

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;
5 голосов
/ 05 декабря 2008

Вы можете взять среднее значение буфера, полученное за выполнение в течение периода активности экземпляра:

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
2 голосов
/ 13 декабря 2016

полная информация, которую я получил от askTom-Oracle. Я надеюсь, что это поможет вам

select * 
from v$sql 
where buffer_gets > 1000000 
or disk_reads > 100000 
or executions > 50000 
2 голосов
/ 16 января 2015

Следующий запрос возвращает операторы SQL, которые выполняют большое количество операций чтения с диска (также включает пользователя-нарушителя и количество выполнений запроса):

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

Запустите запрос как SYS и настройте количество операций чтения с диска в зависимости от того, что вы считаете чрезмерным (100 000 работ для меня).

Я использовал этот запрос совсем недавно, чтобы отследить пользователей, которые отказываются использовать Explain Plans перед выполнением своих заявлений.

Я нашел этот запрос в старой книге по настройке Oracle SQL (которой у меня, к сожалению, больше нет), поэтому извиняюсь, но не приписываю.

2 голосов
/ 25 ноября 2008

Это зависит от того, какая у вас версия oracle, для 9i и ниже Statspack - это то, что вам нужно, 10g и выше, вы хотите awr , оба эти инструмента дадут вам top sql's и множество других вещей.

1 голос
/ 25 ноября 2008

Есть несколько возможных способов сделать это, но есть Google для tkprof

Там нет графического интерфейса ... это полностью командная строка и, возможно, пугающее прикосновение для начинающих Oracle; но это очень мощный.

Эта ссылка выглядит как хорошее начало:

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

0 голосов
/ 25 ноября 2008

При поиске я получил следующий запрос, который выполняет работу с одним допущением (время выполнения запроса> 6 секунд)


ВЫБЕРИТЕ имя пользователя, sql_text, sofar, totalwork, ед.

ОТ v $ sql, v $ session_longops

ГДЕ sql_address = адрес И sql_hash_value = hash_value

ORDER BY адрес, hash_value, child_number;


Я думаю, что в приведенном выше запросе будут перечислены детали для текущего пользователя.

Комментарии приветствуются !!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...