我在生产(Oracle)中运行此查询,并且需要超过3分钟。有没有办法减少执行时间? svc_order和事件表都包含近100万条记录。
select 0 test_section, count(1) count, 'DD' test_section_value
from svc_order so, event e
where so.svc_order_id = e.svc_order_id
and so.entered_date >= to_date('01/01/2012', 'MM/DD/YYYY')
and e.event_type = 230 and e.event_level = 'O'
and e.current_sched_date between
to_date( '09/01/2010 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
and to_date('09/29/2013 23:59:59', 'MM/DD/YYYY HH24:MI:SS')
and (((so.sots_ta = 'N') and (so.action_type = 0))
or ((so.sots_ta is null) and (so.action_type = 0))
or ((so.sots_ta = 'N') and (so.action_type is null)))
and so.company_code = 'LL'
答案 0 :(得分:1)
看看你所说的你无法创建索引。我希望查询在表上进行全表扫描。请尝试平行提示。
select /*+ full(so) parallel(so, 4) */ 0 test_section, count(1) count, 'DD' test_section_value
from svc_order so, event e
where so.svc_order_id = e.svc_order_id
and so.entered_date >= to_date('01/01/2012', 'MM/DD/YYYY')
and e.event_type = 230 and e.event_level = 'O'
and e.current_sched_date between
to_date( '09/01/2010 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
and to_date('09/29/2013 23:59:59', 'MM/DD/YYYY HH24:MI:SS')
and (((so.sots_ta = 'N') and (so.action_type = 0))
or ((so.sots_ta is null) and (so.action_type = 0))
or ((so.sots_ta = 'N') and (so.action_type is null)))
and so.company_code = 'LL'
答案 1 :(得分:0)
你可以至少使用COALESCE()
(或者它的oracle等价物IFNULL()
)来避免三重AND / OR列表注意:这不会出现 sots_ta和action_type都是NULL。
SELECT 0 test_section, count(1) count, 'DD' test_section_value
FROM svc_order so
JOIN event e ON so.svc_order_id = e.svc_order_id
WHERE e.event_type = 230 and e.event_level = 'O'
AND so.entered_date >= to_date('01/01/2012', 'MM/DD/YYYY')
AND e.current_sched_date >= to_date('09/01/2010 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
AND e.current_sched_date < to_date('10/01/2013 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
AND COALESCE(so.sots_ta, 'N') = 'N'
AND COALESCE(so.action_type, 0) = 0
AND so.company_code = 'LL'
我用普通的t >= low AND t. < high)
测试替换了它,因为我不喜欢between
的语义。我将FROM kommalist
替换为JOIN
因为我喜欢加入更好。
答案 2 :(得分:0)
我们不能有其他索引但是表格必须至少具有完整的主键含义,那么是否有一个?这应该至少导致索引,非/群集,任何东西。 看看它让我们尝试使用它。
如果表是一个堆,并且我们想要按原样处理它,那么我们应该通过应用相应的where过滤器然后组合该结果集来单独减少每个表中的行数。 在您的查询中,仅表示完整结果列依赖于基表是count(1)。其他两列是常量。 因为还有JOIN / Cartesian产品等......会引导数据库引擎寻找索引,所以改用INTERSECT,我觉得在你的情况下应该更好。 您可以执行的其他一些更改: 避免在WHERE条件列的右侧使用TO_DATE或任何类型的函数。在本地变量中准备数据并在查询中使用本地变量。 你还需要检查使用&gt; =比BETWEEN有任何好的性能提升吗?
我已经修改了查询并且还合并了一个冗余where条件。 请记住,如果此更改现在适用于您,并不意味着它始终有效。作为儿子你的桌子开始点击更多数据,这些数据符合那些WHERE条件,这个swill再次回来作为慢查询。因此,从短期来看,这可能有效,但从长期来看,你必须考虑其他选择
1) for example Indexed Views on top of this tables
2) Create same tables with different name and sync data
between new and original table using “Insert/Update/Delete Trigger”.
SELECT COUNT(1) AS [COUNT], 'DD' test_section_value ,0 test_section
FROM
(
SELECT so.svc_order_id
FROM svc_order so
WHERE so.entered_date >= to_date('01/01/2012', 'MM/DD/YYYY')
AND so.company_code = 'LL'
INTERSECT
SELECT e.svc_order_id
FROM event e
WHERE e.event_type = 230
AND e.event_level = 'O'
AND e.current_sched_date BETWEEN
to_date('09/01/2010 00:00:00','MM/DD/YYYY HH24:MI:SS')
AND to_date('09/29/2013 23:59:59','MM/DD/YYYY HH24:MI:SS')
AND (
(( so.sots_ta = 'N' ) AND ( so.action_type IS NULL OR so.action_type = 0))
OR
(( so.sots_ta IS NULL ) AND ( so.action_type = 0 ))
--or ((so.sots_ta = 'N') and (so.action_type is null))
)
)qry1
答案 3 :(得分:0)
首先,确保统计数据是最新的。
begin
dbms_stats.gather_table_stats('[schema]', 'svc_order');
dbms_stats.gather_table_stats('[schema]', 'event');
end;
/
此查询是两个小表之间非常简单的连接,但具有复杂谓词。
你几乎可以肯定不想要重新编写所有查询,以寻找一些能让一切运行得很快的神奇语法。是的,在某些罕见的情况下,BETWEEN
无效,或者将谓词移动到内联视图帮助,或者用INTERSECT
替换连接可能会有所帮助。但这对我来说听起来像cargo-cult programming。问问自己,为什么这些变化会有什么不同?如果这些类型的更改总能提高性能,为什么Oracle不会在内部翻译查询?
通常,您应该尝试向优化器提供更好的信息,以便做出更好的决策。通常,这与使用默认设置收集统计信息一样简单。有些谓词太复杂了,为此你应该尝试使用
dynamic sampling,例如/*+ dynamic_sampling(6) */
。或者可能
添加一些histograms。或者像这样添加expression statistic:
SELECT
DBMS_STATS.CREATE_EXTENDED_STATS(null,'SVC_ORDER',
'(((so.sots_ta = 'N') and (so.action_type = 0))
or ((so.sots_ta is null) and (so.action_type = 0))
or ((so.sots_ta = 'N') and (so.action_type is null)))'
)
FROM DUAL;
--Don't forget to re-gather statistics after this.
优化器可能低估了行数,并使用嵌套循环而不是散列连接。在为其提供更多信息之后,理想情况下它将开始使用散列连接。但是在某些时候,在您尝试了上述方法以及可能的许多其他功能之后,您可以告诉它使用哪种连接。这将是@Florin Ghita的建议,/*+use_hash(so e)*/
。