2

我有以下要求。

我想获取特定日期(当天)和特定商店(例如 12)的员工的工作时间表。此外,还有其他商店(13)的员工会来为商店(12)工作,而商店12的员工可以为其他商店工作。

如果员工标记他们的出席,状态表将存储出席/缺席的详细信息。

我想从staffschedules 中获取1) 商店12 的员工日程安排,无论staffstatus 在特定日期是否有条目。

2)staffschedules中所有来自其他门店的日程,通过staffstatus拒绝去其他门店的员工的日程(如果条目在状态表中,我需要检索,否则什么都没有)

2 表:

  1. 时间表
  2. 状态 ----> 员工在场/缺席详情

我写了下面的查询。运行平均需要 30 秒。在最坏的情况下,93 秒。

STAFFSCHEUDLES TABLE SCHEMA: 

CREATE TABLE "STAFFSCHEDULES"
 (
"STORE_ID" VARCHAR2(75 BYTE) NOT NULL ENABLE,
"START_DATE" DATE NOT NULL ENABLE,
"JOB_ID"             VARCHAR2(22 BYTE) NOT NULL ENABLE,
"START_TIME"   VARCHAR2(5 BYTE) NOT NULL ENABLE,   
"END_DATE" DATE NOT NULL ENABLE,
"END_TIME" VARCHAR2(5 BYTE) NOT NULL ENABLE,
"JOBNAME"       VARCHAR2(1500 BYTE)  
CONSTRAINT "PK_STAFFSCHEDULES" PRIMARY KEY ("STORE_ID", "START_DATE", "JOB_ID", "START_TIME") 

CREATE UNIQUE INDEX "PK_STAFFSCHEDULES" ON "STAFFSCHEDULES"
 (
"STORE_ID", "START_DATE", "JOB_ID", "START_TIME"
 )

CREATE INDEX "IDX1_STAFFSCHEDULES_STORSTDT" ON "STAFFSCHEDULES"
 (
  "STORE_ID",
  "START_DATE"
   )

CREATE INDEX "STAFFSCHEDULES_IDX" ON "STAFFSCHEDULES"
  (
  "JOB_ID"
  )   


STAFFSTATUS TABLE SCHEMA: 


CREATE TABLE "STAFFSTATUS"
 (
"JOB_SEQ_ID" NUMBER(10,0) NOT NULL ENABLE,
"JOB_ID"      VARCHAR2(15 BYTE) NOT NULL ENABLE,
"STORE_ID"    VARCHAR2(4 BYTE) NOT NULL ENABLE,
"JOB_DATE" DATE NOT NULL ENABLE,
"STATUS"      VARCHAR2(1 BYTE) DEFAULT 'N'  ,
"SERVER_DATE"   DATE  
CONSTRAINT "PK_STAFFSTATUS" PRIMARY KEY ("JOB_SEQ_ID") 
CONSTRAINT "UK_STAFFSTATUS" UNIQUE ("JOB_ID", "STORE_ID", "JOB_DATE") 
 )

CREATE INDEX "INDEX_STAFFSTATUS" ON "STAFFSTATUS"
 (
"STORE_ID",
"STATUS"
  )

CREATE INDEX "INDEX_STAFFSTATUS_JOB_DT" ON "STAFFSTATUS"
(
"STORE_ID",
"JOB_DATE",
"STATUS"
 )

CREATE UNIQUE INDEX "PK_STAFFSTATUS" ON "STAFFSTATUS"
 (
"JOB_SEQ_ID"
 )

CREATE UNIQUE INDEX "UK_STAFFSTATUS" ON "STAFFSTATUS"
 (
"JOB_ID", "STORE_ID", "JOB_DATE"
 )

 CREATE INDEX "INDEX_STAFFSTATUS_UPDT" ON "STAFFSTATUS"
   (
    "STORE_ID",
  "SERVER_DATE"
    )

查询时间表:

           SELECT *                      
              From StaffSchedules  
              WHERE store_id='15'                 
              AND ((start_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY')) AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+(1-1/24/60/60)
                  AND TO_CHAR(start_date,'HH24:MI') <= start_time)
                  OR((end_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1/24/60/60 AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1)
                  AND TO_CHAR(end_date,'HH24:MI') >= end_time))

              AND job_id NOT IN
               (SELECT distinct s2.job_id
                FROM staffschedules s2 
                WHERE s2.store_id=store_id                  
                AND ((s2.start_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY')) AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+(1-1/24/60/60)
                   AND TO_CHAR(s2.start_date,'HH24:MI') <= s2.start_time)
                   OR((s2.end_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1/24/60/60 AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1)
                   AND TO_CHAR(s2.end_date,'HH24:MI') >= s2.end_time))
                AND SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,8) = 'NOTALLOCATED') 

              AND job_id NOT IN (

                       Select job_Id From staffStatus Where Trunc(job_Date)=Trunc(to_date('07/08/2013','MM/DD/YYYY')) And Store_Id!='15')           


       UNION ALL

               SELECT *                       
                    From StaffSchedules ss
                    Right Outer Join staffStatus status On Es.job_Id=status.job_Id And status.Store_Id<>ss.Store_Id And 
                      (Trunc(status.job_Date)=Trunc(ss.Start_Date) Or Trunc(status.job_Date)=Trunc(ss.End_Date)) 

                    AND ((start_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY')) AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+(1-1/24/60/60)
                  AND TO_CHAR(start_date,'HH24:MI') <= start_time)
                  OR((end_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1/24/60/60 AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1)
                  AND TO_CHAR(end_date,'HH24:MI') >= end_time))

                AND job_id NOT IN
                 (SELECT distinct s2.job_id
                  FROM staffschedules s2 
                  WHERE s2.store_id=store_id                  
                  AND ((s2.start_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY')) AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+(1-1/24/60/60)
                    AND TO_CHAR(s2.start_date,'HH24:MI') <= s2.start_time)
                    OR((s2.end_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1/24/60/60 AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1)
                   AND TO_CHAR(s2.end_date,'HH24:MI') >= s2.end_time))
                 AND SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,8) = 'NOTALLOCATED') 


              AND  status.store_id='15' AND TRUNC(status.job_date)=TRUNC(to_date('07/08/2013','MM/DD/YYYY'))            
              ORDER BY job_id,start_date,start_time;                  

执行计划:

-----------------------------------------------------------------------------------------------------    -------------
| Id  | Operation                       | Name                           | Rows  | Bytes | Cost    (%CPU)| Time     |
 -----------------------------------------------------------------------------------------------------   -------------
|   0 | SELECT STATEMENT                |                                |    41 | 10865 |      37990   (1)| 00:07:36 |
|   1 |  SORT ORDER BY                  |                                |    41 | 10865 | 37989  (67)| 00:07:36 |
|   2 |   UNION-ALL                     |                                |       |          |            |          |
|   3 |    NESTED LOOPS ANTI            |                                |     1 |   265 | 12649   (1)| 00:02:32 |
|   4 |     NESTED LOOPS ANTI           |                                |     1 |   146 | 12620   (1)| 00:02:32 |
|*  5 |      TABLE ACCESS BY INDEX ROWID| STAFFSCHEDULES                 |   109 | 13734 | 12401   (1)| 00:02:29 |
|*  6 |       INDEX RANGE SCAN          | IDX1_STAFFSCHEDULES_STORSTDT   | 65068 |       |   410   (1)| 00:00:05 |
|*  7 |      INDEX RANGE SCAN           | UK_STAFFSTATUS                 |   137K|  2694K|     2   (0)| 00:00:01 |
|*  8 |     TABLE ACCESS BY INDEX ROWID | STAFFSCHEDULES                 |     1 |   119 |    29   (0)| 00:00:01 |
|*  9 |      INDEX RANGE SCAN           | STAFFSCHEDULES_IDX             |    83 |       |     2   (0)| 00:00:01 |
|  10 |    NESTED LOOPS ANTI            |                                |    40 | 10600 | 25340   (1)| 00:05:05 |
|  11 |     NESTED LOOPS                |                                |    40 |  5840 | 24820   (1)| 00:04:58 |
|  12 |      TABLE ACCESS BY INDEX ROWID| STAFFSTATUS                    |  2208 | 44160 |  2931   (1)| 00:00:36 |
|* 13 |       INDEX RANGE SCAN          | INDEX_STAFFSTATUS_SCHD_DT      |  2208 |       |  1525   (1)| 00:00:19 |
|* 14 |      TABLE ACCESS BY INDEX ROWID| STAFFSCHEDULES                 |     1 |   126 |    29   (0)| 00:00:01 |
|* 15 |       INDEX RANGE SCAN          | STAFFSCHEDULES_IDX             |    83 |       |     2   (0)| 00:00:01 |
|* 16 |     TABLE ACCESS BY INDEX ROWID | STAFFSCHEDULES                 |     1 |   119 |    13   (0)| 00:00:01 |
|* 17 |      INDEX RANGE SCAN           | PK_STAFFSCHEDULES              |     1 |       |    12   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------    -------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - filter(("START_DATE"<=TO_DATE(' 2013-07-08 23:59:59', 'syyyy-mm-dd hh24:mi:ss') AND 
          "START_DATE">=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND 
          "START_TIME">=TO_CHAR(INTERNAL_FUNCTION(START_DATE"),'HH24:MI') OR 
          "END_DATE"<=TO_DATE(' 2013-07-09 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND 
          "END_DATE">=TO_DATE(' 2013-07-08 00:00:01', 'syyyy-mm-dd hh24:mi:ss') AND 
          "END_TIME"<=TO_CHAR(INTERNAL_FUNCTION("END_DATE"),'HH24:MI')))

   6 - access("STORE_ID"='15')
   7 - access("JOB_ID"="JOB_ID")
       filter(TRUNC(INTERNAL_FUNCTION("JOB_DATE"))=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd 
          hh24:mi:ss') AND "STORE_ID"<>'15')
   8 - filter("S2"."STORE_ID"='15' AND ("S2"."START_DATE"<=TO_DATE(' 2013-07-08 23:59:59', 
          'syyyy-mm-dd hh24:mi:ss') AND "S2"."START_DATE">=TO_DATE(' 2013-07-08 00:00:00',     'syyyy-mm-dd 
          hh24:mi:ss') AND "S2"."START_TIME">=TO_CHAR(INTERNAL_FUNCTION("S2"."START_DATE"),'HH24:MI'
          ) OR "S2"."END_DATE"<=TO_DATE(' 2013-07-09 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND 
          "S2"."END_DATE">=TO_DATE(' 2013-07-08 00:00:01', 'syyyy-mm-dd hh24:mi:ss') AND 
          "S2"."END_TIME"<=TO_CHAR(INTERNAL_FUNCTION("S2"."END_DATE"),'HH24:MI')) AND 
          SUBSTR("S2"."JOBNAME",INSTR("S2"."JOBNAME",'/',1,7)+1,8)='NOTALLOCATED')
   9 - access("JOB_ID"="S2"."JOB_ID")
  13 - access("STATUS"."STORE_ID"='15')
   filter(TRUNC(INTERNAL_FUNCTION("STATUS"."JOB_DATE"))=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd 
          hh24:mi:ss'))
  14 - filter(("START_DATE"<=TO_DATE(' 2013-07-08 23:59:59', 'syyyy-mm-dd hh24:mi:ss') AND 
          "START_DATE">=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND 
          "START_TIME">=TO_CHAR(INTERNAL_FUNCTION("START_DATE"),'HH24:MI') OR 
          "END_DATE"<=TO_DATE(' 2013-07-09 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND 
          "END_DATE">=TO_DATE(' 2013-07-08 00:00:01', 'syyyy-mm-dd hh24:mi:ss') AND 
          "END_TIME"<=TO_CHAR(INTERNAL_FUNCTION("END_DATE"),'HH24:MI')) AND 
          "STATUS"."STORE_ID"<>"STORE_ID" AND (TRUNC(INTERNAL_FUNCTION("STATUS"."JOB_DATE"))=TRUNC(INTERNAL_FUNCT
          ION("START_DATE")) OR TRUNC(INTERNAL_FUNCTION("STATUS"."JOB_DATE"))=TRUNC(INTERNAL_FUNCTION("
          END_DATE"))) AND "STORE_ID"<>'15')
  15 - access("STATUS"."JOB_ID"="JOB_ID")
  16 - filter(("S2"."STORE_ID"='15' AND ("S2"."START_DATE"<=TO_DATE(' 2013-07-08 23:59:59', 
          'syyyy-mm-dd hh24:mi:ss') AND "S2"."START_DATE">=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd 
          hh24:mi:ss') AND "S2"."START_TIME">=TO_CHAR(INTERNAL_FUNCTION("S2"."START_DATE"),'HH24:MI'
          ) OR "S2"."END_DATE"<=TO_DATE(' 2013-07-09 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND 
          "S2"."END_DATE">=TO_DATE(' 2013-07-08 00:00:01', 'syyyy-mm-dd hh24:mi:ss') AND 
          "S2"."END_TIME"<=TO_CHAR(INTERNAL_FUNCTION("S2"."END_DATE"),'HH24:MI')) AND 
          SUBSTR("S2"."JOBNAME",INSTR("S2"."JOBNAME",'/',1,7)+1,8)='NOTALLOCATED')
  17 - access("S2"."STORE_ID"="STORE_ID" AND "JOB_ID"="S2"."JOB_ID")
      filter("JOB_ID"="S2"."JOB_ID" AND "S2"."STORE_ID"<>'15')

样本 Staffschedule 数据:

storeid  job_id       startdate          starttime           enddate          endtime   jobname
 12         1     2013-07-11 09:00:00     09:00         2013-07-11 18:00:00     10:00     class A
 12         1     2013-07-11 09:00:00     10:00         2013-07-11 18:00:00     11:00     class B
 12         1     2013-07-11 09:00:00     11:00         2013-07-11 18:00:00     18:00     class C

请在这个问题上帮助我。

提前致谢

4

2 回答 2

1

好的,问题数据有很大的变化,所以让我们从头开始检查它。

首先,在查询文本中存在一个未指定的事物:

AND SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,8) = 'NOTALLOCATED')

查询中没有带别名ses2的表,所以我不知道如何处理那个东西。只注意它永远不会评估为,true因为length('NOTALLOCATED')超过 8。所以从答案中删除了这个条件。

影响查询性能的主要因素是NOT IN条件的过度使用。在大多数情况下,此类条件必须更改为针对主查询中的字段的简单测试。
在来自问题的查询中,我们有这样的情况:

select 
  t.*
from
  my_table t
where 
  <big-basket-of-conditions-here>
  and
  t.field_1 not in ( select t.field_1 
                     from my_table t
                     where 
                       <same-big-basket-of-conditions>     
                       and
                       <one_more_test>
                   )  

必须更改为

select 
  t.*
from
  my_table t
where 
  <big-basket-of-conditions-here>
  and
  not (<one-more-test>)

例如,您有:

          AND job_id NOT IN
           (SELECT distinct s2.job_id
            FROM staffschedules s2 
            WHERE s2.store_id=store_id                  
            AND ((s2.start_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY')) AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+(1-1/24/60/60)
               AND TO_CHAR(s2.start_date,'HH24:MI') <= s2.start_time)
               OR((s2.end_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1/24/60/60 AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1)
               AND TO_CHAR(s2.end_date,'HH24:MI') >= s2.end_time))
            AND SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,8) = 'NOTALLOCATED') 

可以更改为

            AND SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,8) <> 'NOTALLOCATED') 

没有子查询和NOT IN.
如果您需要连接另一个表来执行测试,最好在主选择中执行:执行外部连接,然后测试字段:

select * from (
  select
    ss.*,
    nvl(SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,12),'X') alloc_flag
  from
    staffschedules ss,
    some_table     ses2
  where
    ses2.some_field (+) = ss.some_field and ...
)
where alloc_flag <> 'NOTALLOCATED'

这种情况的另一个很好的例子是这种情况:

AND job_id NOT IN (
  Select job_Id 
  From staffStatus 
  Where Trunc(job_Date)=Trunc(to_date('07/08/2013','MM/DD/YYYY')) And Store_Id!='15'
)           

它包含两个不好的东西。上面讨论了其中一个,接下来是!=in 条件的用法。这样的条件消除了有效索引使用的任何可能性。在这种情况下,最糟糕的是,所有索引都store_id排在首位,因此数据库引擎必须遍历整个索引以查找所有条件,并且不能回退到另一个job_date排在首位的索引。
因此,可以使用相同的技术重写该条件

select * from (
  select
    ss.*,
    nvl(statuses.store_id,'X') status_store_id
  from
    staffschedules ss,
    staffstatus    statuses
  where
    statuses.job_id (+) = ss.some_field 
    Trunc(job_Date (+)) = Trunc(to_date('07/08/2013','MM/DD/YYYY'))
    and ...
)
where status_store_id = '15'

最后一件事是加入时对字段的功能使用。看起来可能很直观,但对性能不利,因为在这种情况下Trunc(job_date)数据库无法使用索引。job_date所以在这种情况下最好使用边界条件:

    job_Date >= to_date('07/08/2013','MM/DD/YYYY')
    and 
    job_Date < to_date('07/08/2013','MM/DD/YYYY') + 1

最后,我编写了获取完整日程表的示例查询。您可以在此 SQLFiddle上对其进行测试或查看以下内容。它返回指定商店和日期的全套时间表和状态。
因为我不确定是否理解调度逻辑,所以您可以自行过滤查询结果。

with params as (
  -- Just to write parameters only once.
  -- Note that parameter date truncated.
  select   
    trunc(to_date('07/24/2013 07:20','MM/DD/YYYY HH24:MI')) as date_val,
    '15'                                                    as store_id
  from dual
), 
store_jobs_from_schedule as ( 
  -- Select all valid schedules on desired date for specified store with corresponding statuses if any.
  select                        
    scheduled_jobs.job_id            job_id, 
    scheduled_jobs.store_id          schedule_store_id, 
    scheduled_jobs.start_date        schedule_start_date, 
    scheduled_jobs.start_date_time   schedule_start_time,
    scheduled_jobs.end_date          schedule_end_date, 
    scheduled_jobs.end_date_time     schedule_end_time,
    scheduled_jobs.jobname           schedule_job_name,
    status_list.job_seq_id           status_id,       
    status_list.store_id             status_store_id,
    status_list.job_date             status_job_date,
    status_list.status               status
  from 
    (                         
      select  -- get all schedules for specified date and store.
        p.date_val,
        schedules.job_id,
        schedules.store_id,  
        schedules.start_date,
        ( -- Calculate exact start time as date and time value
          trunc(schedules.start_date) +  
          (to_date(schedules.start_time,'hh24:mi') - to_date('00:00','hh24:mi'))
        ) start_date_time,
        schedules.end_date,
        ( -- Calculate exact end time as date and time value
          trunc(schedules.end_date) +  
          (to_date(schedules.end_time,'hh24:mi') - to_date('00:00','hh24:mi'))
        ) end_date_time,
        schedules.jobname
      from 
        params         p,
        staffschedules schedules
      where                                   
        -- scheduled to specified store
        schedules.store_id = p.store_id
        and                                    
        -- start before the end of desired date
        schedules.start_date < p.date_val + 1  
        and                               
        -- end after beginning of desired date
        schedules.end_date >= p.date_val  
    ) 
                scheduled_jobs,
    staffstatus status_list
  where                                                           
    -- Check if schedule start time are valid
    (scheduled_jobs.start_date <= scheduled_jobs.start_date_time) 
    and
    -- Check if schedule end time are valid
    (scheduled_jobs.end_date >= scheduled_jobs.end_date_time)
    and                          
    -- Link status by staff and date if any - only on desired date, 
    -- not for full schedule length
    status_list.job_id (+) = scheduled_jobs.job_id
    and
    status_list.job_date (+) >= scheduled_jobs.date_val
    and
    status_list.job_date (+) < scheduled_jobs.date_val + 1
),
store_stuff_jobs as (
  -- Select all statuses for specified date and store and link it to corresponding schedules if any
  select -- clear data in invalid schedules 
    job_id                                                                   job_id,    
    decode(is_valid_schedule,'N', null,               schedule_store_id)   schedule_store_id, 
    decode(is_valid_schedule,'N', cast(null as date), schedule_start_date) schedule_start_date,
    decode(is_valid_schedule,'N', cast(null as date), schedule_start_time) schedule_start_time,
    decode(is_valid_schedule,'N', cast(null as date), schedule_end_date)   schedule_end_date,
    decode(is_valid_schedule,'N', cast(null as date), schedule_end_time)   schedule_end_time,
    decode(is_valid_schedule,'N', null,               schedule_job_name)   schedule_job_name,
    status_id                                                                status_id,       
    status_store_id                                                          status_store_id,
    status_job_date                                                          status_job_date,
    status                                                                   status
  from (  
    select -- Calculate if selected schedule are valid             
      job_id, 
      schedule_store_id, 
      schedule_start_date, 
      schedule_start_time,
      schedule_end_date, 
      schedule_end_time,
      schedule_job_name,
      status_id,       
      status_store_id,
      status_job_date,
      status,
      ( -- Calculate flag to check if times of schedules are valid 
        case
          when  
            (schedule_start_date > schedule_start_time)
            or
            (schedule_end_date < schedule_end_time)
          then 'N'
          else 'Y'
        end        
      )   is_valid_schedule
    from (
      select
        status_list.job_id          job_id, 
        schedules.store_id          schedule_store_id, 
        schedules.start_date        schedule_start_date, 
        ( -- Calculate exact start time as date and time value
          trunc(schedules.start_date) +  
          (to_date(schedules.start_time,'hh24:mi') - to_date('00:00','hh24:mi'))
        )                           schedule_start_time,
        schedules.end_date          schedule_end_date, 
        ( -- Calculate exact end time as date and time value
          trunc(schedules.end_date) +  
          (to_date(schedules.end_time,'hh24:mi') - to_date('00:00','hh24:mi'))
        )                           schedule_end_time,
        schedules.jobname           schedule_job_name,
        status_list.job_seq_id      status_id,       
        status_list.store_id        status_store_id,
        status_list.job_date        status_job_date,
        status_list.status          status
      from
        params         p, 
        staffstatus    status_list,
        staffschedules schedules
      where
        status_list.job_date >= p.date_val     
        and
        status_list.job_date < p.date_val + 1    
        and
        status_list.store_id = p.store_id
        and                                    
        -- Link schedules for same staff on same date if any. 
        -- Even schedules to same store, because we need exactly same  
        -- record as in first query to eliminate duplicates on last step.
        schedules.job_id (+) = status_list.job_id
        and
        schedules.start_date (+) < trunc(status_list.job_date) + 1  -- start before the end of desired date
        and
        schedules.end_date (+) >= trunc(status_list.job_date)  -- end after beginning of desired date
    )
  )  
)
  select  
    -- records comes from schedules
    job_id, 
    schedule_store_id store_id, 
    schedule_store_id, 
    schedule_start_date, 
    schedule_start_time,
    schedule_end_date, 
    schedule_end_time,
    schedule_job_name,
    status_id,       
    status_store_id,
    status_job_date,
    status
  from 
    store_jobs_from_schedule
union -- duplicates eliminated
  select  
    -- records comes from status
    job_id, 
    status_store_id store_id,
    schedule_store_id, 
    schedule_start_date, 
    schedule_start_time,
    schedule_end_date, 
    schedule_end_time,
    schedule_job_name,
    status_id,       
    status_store_id,
    status_job_date,
    status
  from 
    store_stuff_jobs
order by 
  job_id, schedule_start_date, schedule_start_time
于 2013-07-07T09:41:51.383 回答
0

您的主过滤器已打开date。所以你会想要按日期索引。但这只有在某个日期的记录数明显少于表中的记录数时才有意义。说 < 5%。因此,您的第一个最佳收益将是索引staffschedules.date(或其他以日期开头的多部分索引)。

您应该使用 sqlplus 中的示例日期单独运行这两个查询,并查看时间花费在哪里。如果时间花在第一个查询上,那么这将是date索引甚至是date-store索引。这部分不应该很慢。

如果 UNION 的第二部分很慢,请将其分成两部分并分别调查:

SELECT *
  FROM staffschedules
  WHERE date = v_date
    AND store <> v_store

SELECT staffid
  FROM staffstatus
  WHERE store=v_store
    AND jobdate=v_date

如果第一部分很慢,那么再次是日期索引。如果第二个很慢,那么它可能需要在staffstatus.jobdate. 如果每个都运行得相当快,那么您必须查看 是如何staffid连接的,但这很可能是jobdate.

于 2013-07-06T15:32:17.683 回答