ORACLE中这个运行4秒左右的SQL语句如何优化?我想查询少用点时间

Posted

技术标签:

【中文标题】ORACLE中这个运行4秒左右的SQL语句如何优化?我想查询少用点时间【英文标题】:How to optimize this SQL statement that run about 4 seconds in ORACLE?I want to query and use less time 【发布时间】:2020-05-08 16:17:10 【问题描述】:

我项目中的以下 sql 运行大约 4 秒。TB_Order 进行了全表扫描。 TB_Order的state字段有索引。表的数据量是2000万,E和P的数据量小于50。这个SQL可以优化。我用过UNION ALL,是不是?你有更好的sql吗?

--The first version
SELECT T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE (T.STATE = 'E' OR (T.STATE = 'P' AND SYSDATE > T.EFFECTIVE_DATE))
AND (T.PRIORITY <= 100 OR T.PRIORITY IS NULL)
AND ROWNUM <= :1

--The second version
SELECT * FROM (
SELECT T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE (T.STATE = 'E')
AND (T.PRIORITY <= 100 OR T.PRIORITY IS NULL)
UINON ALL 
SELECT T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE (T.STATE = 'P' AND SYSDATE > T.EFFECTIVE_DATE)
AND (T.PRIORITY <= 100 OR T.PRIORITY IS NULL)
)
where ROWNUM <= :1

【问题讨论】:

请提供样本数据、期望的结果以及您正在实施的逻辑的解释。作为记录,您提到了一个查询的时间——然后您显示了两个查询。令人困惑。 如果不知道您的数据配置文件、T.STATE 列和 T.PRIORITY 也是如此。如果 您是否尝试添加命中以强制对 STATE 进行索引扫描? 您应该在查询使用的执行计划中检查的第一项。请参阅here 如何获取它以及您必须提供哪些其他数据才能获得帮助。此外,如果 STATE 列中的数据是 skew (即有很多行具有某些值,而少数行具有其他值)您应该检查的是列 histogram. @flower 使用此查询检查直方图:select histogram, column_name from all_tab_columns where table_name = 'TB_ORDER'; 如果没有,请尝试收集统计数据以生成一个:begin dbms_stats.gather_table_stats(user, 'TB_ORDER'); end; 【参考方案1】:

不是最好的方法,消除 OR 并强制 INDEX 扫描,尝试没有 HINT 的解释计划,看看是否使用了 TB_ORDER.STATE 上的索引。只有在不使用索引时才添加提示。还建议在 TB_ORDER 表上运行统计信息。

SELECT * FROM
(SELECT /*+ INDEX(T STATE_NDX) */ T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE T.STATE = 'E'                        
AND DECODE(T.PRIORITY,null,0,T.PRIORITY) <= 100
AND ROWNUM <= :1
UNION ALL
SELECT /*+ INDEX(T STATE_NDX) */ T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE T.STATE = 'P' 
AND SYSDATE > T.EFFECTIVE_DATE
AND DECODE(T.PRIORITY,null,0,T.PRIORITY) <= 100
AND ROWNUM <= :1)

【讨论】:

【参考方案2】:

你可以用IN代替UNION。sql只会查询一次表。

  SELECT T.ORDER_ID, T.PRIORITY, T.SUB_TASK
   FROM TB_ORDER T
  WHERE T.STATE IN ('E', 'P')
  AND (CASE
     WHEN (T.STATE = 'P' AND SYSDATE > T.EFFECTIVE_DATE) THEN
      1
     WHEN T.STATE = 'E' THEN
      1
     ELSE
      0
   END) = 1
 AND (T.PRIORITY <= 100 OR T.PRIORITY IS NULL)
 AND ROWNUM <= :1

【讨论】:

以上是关于ORACLE中这个运行4秒左右的SQL语句如何优化?我想查询少用点时间的主要内容,如果未能解决你的问题,请参考以下文章

Oracle查询速度优化问题

经典案例:如何优化Oracle使用DBlink的SQL语句

Oracle SQL 性能优化

如何在 Oracle SQL 中优化或在没有循环的情况下执行此操作

oracle存储过程执行很慢sql很快

如何优化SQL语句