sql - order by 子句的性能问题

标签 sql performance oracle oracle11g

我有以下查询,它在执行后从 100000000 返回 20000 条记录..

SELECT * 
  FROM (SELECT a.*, ROWNUM rnum 
          FROM (select TIME,url,bytes 
                  FROM (SELECT TO_CHAR ("5mintime",'YYYY-MM-DD HH24:MI:SS') AS TIME, url, BYTES 
                          FROM available_web_details  
                         WHERE "5mintime" >= TIMESTAMP '2012-02-10 00:00:00' 
                           AND "5mintime" <= TIMESTAMP '2012-02-13 23:59:59' 
                           AND username = 'asha1328874833' 
                           AND CATEGORY = 'None240001'AND domain = '1328874833.vmware.com.'
                           AND (appid IN ('216.198.204.192id','216.198.207.0id','216.198.211.64id','216.198.211.128id','216.198.212.0id', '216.198.214.128id','216.198.214.192id','216.198.218.0id','216.198.220.192id','216.198.222.0id','216.198.223.32id','216.198.228.128id','216.198.229.128id',.....))) 
                      ORDER BY TIME DESC) a 
                 WHERE ROWNUM <= 10) 
         WHERE rnum > 0

执行它大约需要 5 分钟。但是当我删除 order by 子句时,它会在 4 秒内执行。你能建议我如何提高性能吗?

available_web_details 的 架构:
Name         Null   Type           
------------ ---- -------------- 
5mintime          TIMESTAMP(6)   
USERNAME          VARCHAR2(64)   
HOST              NUMBER         
SRC_ZONE          VARCHAR2(32)   
DOMAIN            VARCHAR2(512)  
DST_ZONE          VARCHAR2(32)   
CONTENT           VARCHAR2(64)   
CATEGORY          VARCHAR2(64)   
URL               VARCHAR2(1024) 
HITS              NUMBER         
BYTES             NUMBER         
APPID             VARCHAR2(32)   
APPLICATION       VARCHAR2(64)   
CATEGORYTYPE      VARCHAR2(64)   
USERGROUP         VARCHAR2(384)  

我在 appid 上有索引,“5mintime” 带有本地分区。 available_web_details 是 1 个月的范围分区表。

最佳答案

让我们从免责声明开始:如果你不删除那个 order by 或开始使用临时表,执行时间是 永远不会 减少到 4s。第二个免责声明:我犯了一个大错误,现在正在纠正;我花了太长时间才意识到这一点。谢谢 Alex Poole

我的观点(我总是有几个)。

  • 评论中提出了一些非常有效的观点,特别是 DimitryB 。如果您一次只显示 10 条记录,那么 20,000 行等于 2,000 页。没有人会费心查看所有这些信息。如果不是一两百,您可以非常安全地将返回的记录数减少到 500。
  • craigmj's answer 提出了一个同样有效的观点,但我想大大扩展它。通过不索引 where 子句中的所有 select 中的所有内容,您 保证 table access by index rowid 。这意味着对于您从最里面的 select 返回的每一行,您都从索引中提取,您还可以重新访问该表。我承认这将是您当前表上的一个可笑的大索引。
  • 您似乎在做比需要的更多的子选择。您可以在主 select 中下订单。您还在别名上方的两个级别引用别名 a。虽然这可能不会导致任何问题,但它有点令人困惑,最终会出现两次 rnum 列。
  • 100m 行正在走向频谱的大端。任何人都不太可能翻阅所有这些内容,而且根据您的评论,报告中并未全部使用它们。虽然对表进行了分区,这将有很大帮助,但 Oracle 仍然需要确定使用哪个分区。
  • 从第 5 点开始,您已经按月对表进行了分区,但只选择了 3 天的数据。我同意这是明智的,但如果您只需要最多一个月的数据就可以轻松访问,那么对于较小的表可能值得按天进行分区?您提到有 2,300 份报告使用此表;如果它们都需要 5 分钟,则应考虑使用诸如此类的极端方法。
  • 有点可悲,但是 url 是否需要为 1024 个字符?

  • 这些要点实际上归结为我的主要建议;减小表的大小。 然后,尽一切可能去除 Oracle 需要做的任何额外工作;甚至将大部分表格变成索引。

    所以,步骤是:
  • 将超过一个月的所有内容归档到单独的表中。每天坚持这样做。
  • 按天对较小的表进行分区。
  • 如果您只需要几天的数据,那么绝对值得考虑创建一个 materialized view ,并且 order by 已经到位。
  • 在这个新的、较小的表上使用“最佳”索引;所以你根本不需要真正接触 table 。我在最佳周围加上了引号,因为这总是有争议的,我的建议可能有点不正确,但通常是 where, group by, order by and select clauses 中的所有列 按照 的顺序降低选择性。这将使您的索引类似于 "5mintime", username, category, domain, appid, url, bytes
  • 尽可能使索引唯一。
  • 确保您的查询没有做任何它不需要做的事情,以减少工作量。这包括返回人类可读的行数。我会像这样重写它:

  • SELECT time, url, bytes, rownum as rnum
      FROM ( SELECT time, url, bytes, rowum as rnum 
               FROM ( SELECT TO_CHAR ("5mintime",'YYYY-MM-DD HH24:MI:SS') AS time
                           , url
                           , bytes 
                        FROM available_web_details  
                       WHERE "5mintime" BETWEEN to_timestamp('2012-02-10 00:00:00','YYYY-MM-DD HH24:MI:SS')
                                AND to_timestamp('2012-02-13 23:59:59','YYYY-MM-DD HH24:MI:SS')
                         AND username = 'asha1328874833' 
                         AND category = 'None240001'
                         AND domain = '1328874833.vmware.com.'
                         AND appid IN ('216.198.204.192id',...) 
                       ORDER BY "5mintime" DESC
                             )
             WHERE rownum <= 10) 
     WHERE rnum > 0
    

    希望这一切都有意义;在一天结束时,您的报告在服务器上完成的工作量以及您希望它们运行的​​速度将决定您想要做什么。

    关于sql - order by 子句的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9441649/

    相关文章:

    java - PDF 抓取 -> MS Access

    Java 销毁变量

    mysql - 更新连接表需要很长时间

    java - 使用maven导出数据库Oracle

    oracle - Oracle 序列的 MAXVALUE 的用途是什么?

    php - 更好的 SQL 搜索引擎

    java - 如何通过排除原则从另一个表中过滤选择

    sql - 哪个提供更快的查询?哪个更干净?加入或加入

    SQL 与...更新

    performance - Matlab 重复矩阵乘法 - 循环与内置性能