Sql 如何减少大数据表的查询执行时间
我正在生产(Oracle)中运行此查询,需要3分钟以上的时间。有没有办法缩短执行时间?svc_顺序和事件表都包含近100万条记录Sql 如何减少大数据表的查询执行时间,sql,database,performance,oracle,Sql,Database,Performance,Oracle,我正在生产(Oracle)中运行此查询,需要3分钟以上的时间。有没有办法缩短执行时间?svc_顺序和事件表都包含近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',
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'
您至少可以通过使用COALESCE()
(或其oracle等价物IFNULL()
)来避免三元组和/或列表注意:这不适用于sots和action类型都为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'
选择0测试部分、计数(1)计数、“DD”测试部分值
从svc_订单so
在so.svc\u order\u id=e.svc\u order\u id上加入事件e
其中e.event_type=230,e.event_level='O'
因此,输入日期>=截止日期('2012年1月1日','MM/DD/YYYY')
和e.当前日程日期>=截止日期('09/01/2010 00:00:00','MM/DD/YYYY HH24:MI:SS')
和e.当前日程日期<截止日期('2013年1月10日00:00:00','MM/DD/YYYY HH24:MI:SS')
并结合(so.sots_ta,'N')='N'
和合并(so.action_type,0)=0
因此,company_code='LL'
我用一个普通的t>=low和t<高)
测试,因为我不喜欢之间的语义。我将kommalist中的替换为连接,因为我更喜欢连接。您至少可以使用COALESCE()
(或其oracle等价物IFNULL()
)来避免三元组和/或列表。注意:这不适用于sots和action类型都为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'
选择0测试部分、计数(1)计数、“DD”测试部分值
从svc_订单so
在so.svc\u order\u id=e.svc\u order\u id上加入事件e
其中e.event_type=230,e.event_level='O'
因此,输入日期>=截止日期('2012年1月1日','MM/DD/YYYY')
和e.当前日程日期>=截止日期('09/01/2010 00:00:00','MM/DD/YYYY HH24:MI:SS')
和e.当前日程日期<截止日期('2013年1月10日00:00:00','MM/DD/YYYY HH24:MI:SS')
并结合(so.sots_ta,'N')='N'
和合并(so.action_type,0)=0
因此,company_code='LL'
我用一个普通的t>=low和t<高)
测试,因为我不喜欢之间的语义。我将kommalist的替换为连接,因为我更喜欢连接。我们不能有额外的索引,但表必须至少有完整的主键,对吗?这至少会产生索引、非/聚集的任何结果。
看看它,试着利用它
若表是一个堆,我们希望按原样处理它,那个么我们应该通过应用各自的where过滤器来分别减少每个表中的行数,然后合并该结果集。
在查询中,唯一表示整个结果列依赖于基表的是count(1)。其他两列是常量。
因为还加入了/笛卡尔积等…。。将引导DB引擎查找索引,所以使用INTERSECT,我觉得在您的情况下应该更好。
您可以执行的其他一些更改:
避免使用WHERE条件列右侧的TO_DATE或任何类型的函数。在局部变量中准备数据,并在查询中使用局部变量。
此外,您还需要检查使用>=是否有任何良好的性能提升
我修改了查询,还合并了一个冗余where条件。
记住,如果这些改变现在对你有效,并不意味着它会一直有效。当您的表开始命中更多的数据时,这些数据将再次以慢查询的形式返回。所以短期内这可能有效,但长期而言,你必须考虑其他选择
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
我们不能有额外的索引,但表必须至少有完整的主键,对吗?这至少会产生索引、非/聚集的任何结果。
看看它,试着利用它
若表是一个堆,我们希望按原样处理它,那个么我们应该通过应用各自的where过滤器来分别减少每个表中的行数,然后合并该结果集。
在查询中,唯一表示整个结果列依赖于基表的是count(1)。其他两列是常量。
因为还加入了/笛卡尔积等…。。将引导DB引擎查找索引,所以使用INTERSECT,我觉得在您的情况下应该更好。
您可以执行的其他一些更改:
避免使用WHERE条件列右侧的TO_DATE或任何类型的函数。在局部变量中准备数据,并在查询中使用局部变量。
此外,您还需要检查使用>=是否有任何良好的性能提升
我修改了查询,还合并了一个冗余where条件。
记住,如果这些改变现在对你有效,并不意味着它会一直有效。当您的表开始命中更多的数据时,这些数据将再次以慢查询的形式返回。所以短期内这可能有效,但长期而言,你必须考虑其他选择
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
首先,确保统计数据是最新的
begin
dbms_stats.gather_table_stats('[schema]', 'svc_order');
dbms_stats.gather_table_stats('[schema]', 'event');
end;
/
此查询是两个小表之间的一个非常简单的联接,但具有复杂的谓词。
几乎可以肯定的是,您不希望为了搜索一些神奇的语法而显著地重写所有查询,这些语法将使所有查询都运行得很快。是的,在一些罕见的情况下,BETWEEN
不起作用,或者将谓词移动到内联视图中会有帮助,或者用INTERSECT
替换连接可能会有帮助。但我觉得这很像。扪心自问,为什么这些变化会有什么不同?如果这些类型的更改总是能提高性能,为什么Oracle不在内部转换查询呢
通常,您应该尝试向优化器提供更好的信息,以便优化器能够做出更好的决策。通常,这与使用默认设置收集统计数据一样简单。有些谓词太复杂了,因此您应该尝试使用
,例如/*+动态_采样(6)*/
。或许
加一些。