2008-11-25 885 views
29

如何在Oracle中发现性能不佳的SQL查询?Oracle中排名前5的耗时SQL查询

Oracle维护共享SQL区域的统计信息,并且每个SQL字符串(v $ sqlarea)包含一行。 但是,我们如何确定哪一个表现不佳呢?

回答

1

有许多的方法可以做到这一点,但有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_idchild_number,并将它们送入这个婴儿: -

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

这说明从SQL缓存和SQL的完整文本的实际计划。

+0

您应该在select中添加elapsed_time,否则会非常令人困惑。 – 2014-11-05 11:37:02

-1

在寻找,我得到了以下查询该做的工作有一个假设(查询执行时间> 6秒)


SELECT用户名,SQL_TEXT,SOFAR,TOTALWORK,单位

从V $ SQL,v $ SESSION_LONGOPS

WHERE SQL_ADDRESS =地址AND SQL_HASH_VALUE = HASH_VALUE

ORDER BY地址,哈希值,CHILD_NUMBER ;


我想上面的查询会列出当前用户的详细信息。

评论欢迎!

+0

该查询不限于当前用户,只有在查询出现在v $ session_longops中时才会起作用。 Longops记录了通过排序,表扫描,索引全面扫描甲骨文是多远。如果由于嵌套循环计划不好而导致查询速度较慢,则不会显示,因为没有冗长的计划。 – 2008-11-26 01:51:16

1

这取决于你拥有哪个版本的oracle,对于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的用户。

我在旧的Oracle SQL调优书中发现了这个查询(我不幸不再有这个),所以很抱歉,但没有归属。

1

我从askTom-Oracle获得的完整信息。我希望它可以帮助你

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