2008-11-25 3 views
29

Как найти неудачные SQL-запросы в Oracle?Топ 5 трудоемких SQL-запросов в Oracle

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

ответ

1

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

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

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

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

+0

Есть ли способ получить данные с помощью sql-запроса? Поддерживает ли Oracle соответствующие данные в некоторых системных таблицах? – 2008-11-25 10:06:00

+0

Он не поддерживает столько данных в системных таблицах, сколько вы получаете с tkprof. См. Мой ответ для быстрого и грязного способа поиска плохих высказываний. tkprof лучше, но вам нужно специально настроить тест и запустить его. – 2008-11-26 01:49:08

42

Я нашел этот 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.

+0

Вы должны добавить elapsed_time в select, иначе это довольно запутанно. – 2014-11-05 11:37:02

-1

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


SELECT, имя пользователя, sql_text, ГНФАР, totalwork, блоки

ОТ V $ SQL, v $ SESSION_LONGOPS

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

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

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

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

+0

Этот запрос не ограничивается текущим пользователем и будет работать только в том случае, если запрос появляется в v $ session_longops. Longops записывает, как далеко через сортировку, сканирование таблицы, полное сканирование индекса Oracle. Если ваш запрос медленный из-за плохого плана вложенных циклов, он не будет отображаться, потому что нет локопов. – 2008-11-26 01:51:16

1

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

4

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

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 
15

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

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; 
1

следующий запрос возвращает 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 перед выполнением своих заявлений.

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

1

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

select * 
from v$sql 
where buffer_gets > 1000000 
or disk_reads > 100000 
or executions > 50000 
Смежные вопросы