提高定期主约会及其例外的SELECT查询性能

时间:2014-02-14 14:23:53

标签: sql sql-server oracle query-optimization firebird

我正在努力优化以下查询(现在需要1:15分钟),但我最好先解释一下我在做什么(长):

我正在为tt_actualstart - tt_actualfinish标识的员工tt_emp_id期间选择(Developer Express)日历活动。
这些事件的特征是tt_type值:

0: single event<br />
1: master recurring event<br />
other: exceptions on the recurring events.
  (These have a `tt_parentid` referencing `tt_calendar_id` of the master event)

4'OR'-ed查询部分是:

  1. 员工期间的单项和主事件
  2. 主人满足1
  3. 要求的所有例外情况
  4. 属于员工的主事件(任何地方)期间的例外情况
  5. 属于3中发现的例外的主事件。
    此查询部分是花费最多时间的部分。
  6. 示意性地:

    Legend:   |-------------------| = selection period
              CAPITALS = selected event
              lowercase = related event
    
    1.                               MASTER
                              |-------------------|
    
    2.        EXCEPTION              master
                              |-------------------|
    
    3.        master                EXCEPTION
                              |-------------------|
    
    4.        MASTER                exception                  
                              |-------------------|
    

    有一个复杂因素影响了这些查询:我无法选择具有所需员工ID的异常。这是因为当Developer Express代码等于master父级的属性时,Developer Express代码不存储异常的约会属性。因此,只能在主父母上完成对员工ID的选择。

    如您所见,第二个OR-ed查询使用第一个OR-ed查询作为子查询;同样为4和3。

    select c.*
    from tt_calendar c
    where 
    ( 
       ( 
          (c.tt_type in (0,1)) and (c.tt_actualstart <= '2014-03-31') and (c.tt_actualfinish >= '2014-01-01') and (c.tt_emp_id= 20652)
       )
    
         or 
    
       (  
          (c.tt_type > 1) and (c.tt_parentid is not null) and  
          (c.tt_parentid in (select c2.tt_calendar_id from tt_calendar c2
                             where (c2.tt_calendar_id=c.tt_parentid) and (c2.tt_actualstart <= '2014-03-31') and (c2.tt_actualfinish >=  '2014-01-01') and (c2.tt_emp_id=20652)
                             )
          )
       )
    
         or
    
       (  
          (c.tt_type > 1) and (c.tt_parentid is not null) and  
          (c.tt_actualstart <= '2014-12-31') and (c.tt_actualfinish >= '2014-01-01') and
          (c.tt_parentid in (select c2.tt_calendar_id from tt_calendar c2 where c2.tt_emp_id=20652))
       )
    
         or
    
       (  
          (c.tt_type = 1) and
          (c.tt_calendar_id in 
            (select tt_parentid from tt_calendar c2 
             where (c2.tt_type > 1) and (c2.tt_parentid is not null) and  
                   (c2.tt_actualstart <=  '2014-03-31') and (c2.tt_actualfinish >= '2014-01-01') and (c2.tt_emp_id=20652)))
       )
    )
    

    tt_actualstarttt_actualfinish上添加索引可以提高15%的速度。 (FireBird)查询计划显示确实正在使用这些索引 除主键tt_calendar_id外没有其他索引。

    我尝试过的另一件事是使用整数TAG字段,该字段由4个单独的UPDATE查询设置,然后选择TAGged记录。
    这实际上会增加执行时间。

    我不确定converting the IN to EXISTS是否有用 - Firebird / SQL / Oracle(我需要三个)都已经优化了吗?

    关于如何改进此查询的更多想法?

    2014年2月17日新增

    在我的测试数据中有一个异常情况,到目前为止所有的答案都错过了,我的(重)第4个查询发现:

    (未找到)仅发生两次事件的重复事件的主ID 27274:2013年12月10日 - 2013年12月11日

    (发现)例外情况27275,其中发生的事件(从2013年12月11日起)移至2014年1月11日(tt_parent_id = 27274)
    在这种情况下,事件被移入选择期间,但主人不在那里。我也需要找到主人。

    BTW这四个结果集有一些重叠,因此在所有情况下都应该是UNION而不是UNION ALL,但我的问题并不清楚。

1 个答案:

答案 0 :(得分:0)

select c.*
from tt_calendar c

where 
   ( 
      (c.tt_type in (0,1)) and (c.tt_actualstart <= '2014-12-31') and (c.tt_actualfinish >= '2014-01-01') and (c.tt_emp_id= 20652)
   )

UNION

select c.*
from tt_calendar c 
inner join tt_calendar c2 on c2.tt_calendar_id=c.tt_parentid
where
   (  
      (c.tt_type > 1) and (c.tt_parentid is not null) and  
       (c2.tt_actualstart <= '2014-12-31') and (c2.tt_actualfinish >= '2014-01-01') and (c2.tt_emp_id=20652)
   )

UNION

select c.*
from tt_calendar c 
inner join tt_calendar c2 on c2.tt_calendar_id=c.tt_parentid
where
   (  
      (c.tt_type > 1) and (c.tt_parentid is not null) and  
      (c.tt_actualstart <= '2014-12-31') and (c.tt_actualfinish >= '2014-01-01') and (c2.tt_emp_id=20652)
   )

UNION

select c.*
from tt_calendar c 
inner join tt_calendar c2 on c.tt_calendar_id=c2.tt_parentid
where

   (  
      (c.tt_type = 1) and (c.tt_emp_id=20652) and
      (c2.tt_type > 1) and (c2.tt_parentid is not null) and  
      (c2.tt_actualstart <=  '2014-12-31') and (c2.tt_actualfinish >= '2014-01-01')
   )
)