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语句如何优化?我想查询少用点时间的主要内容,如果未能解决你的问题,请参考以下文章