如何在Oracle中找到性能不佳的SQL查询?
Oracle维护共享SQL区域的统计信息,每个SQL字符串包含一行(v $ sqlarea).但是,我们怎样才能确定哪一个表现不佳?
我发现这个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语句,这些SQL语句按经过时间排序.随着时间的推移,语句将从缓存中消失,因此当您在中午开始工作时,尝试诊断昨晚的批处理作业可能并不好.
您还可以尝试通过disk_reads和执行进行排序.执行很有用,因为一些不良应用程序发送相同的SQL语句的次数太多.此SQL假定您正确使用绑定变量.
然后,你可以采取sql_id
和child_number
声明,并将它们送入这个婴儿: -
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id', &child));
这显示了SQL缓存的实际计划和SQL的全文.
你可以找到磁盘密集型全表扫描,如下所示:
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;
您可以将实例活动期间的每次执行平均缓冲区获取数取值:
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