假设:
包含事件的视图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秒内运行。对于给定的应用程序来说足够快。
问题:
为什么第一种解决方案与第二种方案相比变慢?我猜这个子查询是为DataView
的每一行执行的,但希望优化器能够解决这个问题。
是否有更高效/更好的方式来进行第一次查询?使用CurrShift.StartTime
比计算应用程序中的时间戳更方便。
@Robbie Toyota:是的,Inst
和StartTime
在两个表格中都是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。
答案 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个小时。