子查询会减慢查询速度

时间:2017-07-19 14:38:04

标签: sql oracle performance oracle10g query-optimization

假设:

  • 包含事件的视图DataView。事件存储时间戳为Inst和数据列。

  • 事件分为特定班次或间隔,从每天06:00,14:00和20:00开始。

  • 视图DataView每班有数百个事件,并有多年积压。

  • 当前班次的开始时间戳存储在表CurrShift中。该列的信息标记为StartTime该表仅包含该行的一行信息。

目标:

从当前班次中检索所有事件,即DataView.Inst >= CurrShift.StartTime

解决方案但速度慢:

SELECT *
FROM DataTable
WHERE Inst >= (SELECT StartTime FROM CurrShift);

查询运行时间超过30分钟。这对于给定的应用程序是不可接受的。

查询速度更快,但仅适用于固定日期

SELECT *
FROM Data_Table
WHERE Inst >= TO_DATE('19.07.2017 14:00:00');

此查询在2.0秒内运行。对于给定的应用程序来说足够快。

问题:

  1. 为什么第一种解决方案与第二种方案相比变慢?我猜这个子查询是为DataView的每一行执行的,但希望优化器能够解决这个问题。

  2. 是否有更高效/更好的方式来进行第一次查询?使用CurrShift.StartTime比计算应用程序中的时间戳更方便。

  3. @Robbie Toyota:是的,InstStartTime在两个表格中都是date类型。

    @dnoeth: 1.)子查询只返回一行。该表仅包含当前班次的开始和结束时间戳及其指定。 2.)无论如何我尝试了MAX(..),没有成功。

    解释计划 我按照罗比的建议执行了解释计划,并看到了计划的巨大差异。但我不知道如何处理这些信息:

    慢查询:

    SELECTED STATEMENT
      HASH JOIN RIGHT OUTER
        TABLE ACCESS FULL
        HASH JOIN RIGHT OUTER
          TABLE ACCESS FULL
          HASH JOIN RIGHT OUTER
            TABLE ACCESS FULL
      ...
    

    快速查询:

    SELECTED STATEMENT
      NESTED LOOPS OUTER
        NESTED LOOPS OUTER
          NESTED LOOPS OUTER
    ...
    

    具有完全不同的引用表,以及用于散列的巨大CPU Coast。

2 个答案:

答案 0 :(得分:0)

尝试使用以下内容避免使用子查询:

DECLARE t Time_Table.Inst%TYPE;
SELECT Inst INTO t FROM Time_Table;
SELECT * FROM Data_Table WHERE Inst >= t;

答案 1 :(得分:0)

这解决了问题2.)但这是一个混乱的方法。 原始快速解决方案中的TO_DATE()可以用SYSDATE替换,而不会有任何明显的性能损失。

<强>回顾:

  • SYSDATE的WHERE子句运行速度相当快

  • 很难计算出移出SYSDATE的开始时间戳

  • 有一张表格提供了开始时间戳

  • 在该表中使用子查询的WHERE子句很慢

<强>解决方案:

  • 使用带有SYSDATE的WHERE子句减少原始数据到当天

  • 将具有WHERE子句和子查询的子集过滤到start-timestamp表中的速度很快,因为它只是原始数据的一小部分

<强>代码:

SELECT *
FROM (
  SELECT *
  FROM Data_Table
  WHERE Inst >= SYSDATE - 1;
)
WHERE Inst >= (SELECT StartTime FROM CurrShift);

问题的执行时间大约是 Fast Solution 的1.5。

关于问题1:

我仍然不知道为什么子查询太慢了。但我学会了更好地解释解释计划。视图是如此复杂和深深嵌套,从那里开始解释计划是一项艰苦的工作。有趣的事实:解释计划期望查询运行9个小时。