2011-06-09 96 views
0

我有一個龐大的查詢,這些查詢已經逐漸發展多年,所有的iv完成都是添加子程序來滿足增長。現在問題是這個查詢需要大約3分鐘的時間來運行。可有一個人幫我優化這個查詢幫助優化SQL查詢

SELECT ENTRY_1.REP_CODE,CONTACT_1.NAME, 
     (select sum((d2.total_goods-d2.total_cost)*et2.sign) 
     from detail d2 
     join entry e2 on d2.entry_id=e2.entry_id 
     join entry_type et2 on et2.entry_type=e2.entry_type 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where ((d2.detail_type = 'O' and d2.charged_qty<d2.qty 
     and d2.nocharge_qty=0) 
     or (d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF')) 
     or ((e2.entry_type = 'SJIN') and (d2.total_goods = 0))) 
     and c2.contact_id=contact_1.contact_id 
     and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) MTD_GP, 
    -- get the month to date sales 
     (select sum((d2.total_goods)*et2.sign) 
     from detail d2 
     join entry e2 on d2.entry_id=e2.entry_id 
     join entry_type et2 on et2.entry_type=e2.entry_type 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where ((d2.detail_type = 'O' and d2.charged_qty<d2.qty 
     and d2.nocharge_qty=0) 
     or (d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF')) 
     or ((e2.entry_type = 'SJIN') and (d2.total_goods = 0))) 
     and c2.contact_id=contact_1.contact_id 
     and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) MTD_SALES, 
    -- 
     (select sum((d2.total_goods-d2.total_cost)*et2.sign) 
     from detail d2 
     join entry e2 on d2.entry_id=e2.entry_id 
     join entry_type et2 on et2.entry_type=e2.entry_type 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where (d2.detail_type = 'O' and d2.charged_qty<d2.qty and d2.nocharge_qty=0) 
     and c2.contact_id=contact_1.contact_id 
     and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) ORD_GP, 

     (select sum((d2.total_goods)*et2.sign) 
     from detail d2 
     join entry e2 on d2.entry_id=e2.entry_id 
     join entry_type et2 on et2.entry_type=e2.entry_type 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where (d2.detail_type = 'O' and d2.charged_qty<d2.qty and d2.nocharge_qty=0) 
     and c2.contact_id=contact_1.contact_id 
     and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) ORD_SALE, 

     (select sum((d2.total_goods-d2.total_cost)*et2.sign) 
     from detail d2 
     join entry e2 on d2.entry_id=e2.entry_id 
     join entry_type et2 on et2.entry_type=e2.entry_type 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF') 
     and c2.contact_id=contact_1.contact_id 
     and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) INV_GP, 

     (select sum((d2.total_goods)*et2.sign) 
     from detail d2 
     join entry e2 on d2.entry_id=e2.entry_id 
     join entry_type et2 on et2.entry_type=e2.entry_type 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF') 
     and c2.contact_id=contact_1.contact_id 
     and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) INV_SALE, 

     (select sum((d2.total_goods-d2.total_cost)*et2.sign) 
     from detail d2 
     join entry e2 on d2.entry_id=e2.entry_id 
     join entry_type et2 on et2.entry_type=e2.entry_type 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where (e2.entry_type = 'SJIN') and (d2.total_goods = 0) 
     and c2.contact_id=contact_1.contact_id 
     and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) EXPEND, 

     (select count(distinct e2.trader_id) 
     from entry e2 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where e2.entry_type in('SORD','SINV','DREC') 
     and c2.contact_id=contact_1.contact_id 
     and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) MTD_PUR, 

     (select count(distinct e2.our_reference) 
     from entry e2 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where e2.entry_type in('SORD') and c2.contact_id=contact_1.contact_id 
     and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) MTD_ORD, 

    (select sum((d1.total_goods-d1.total_cost)*et.sign) 
     from detail d1 
     join entry e1 on d1.entry_id=e1.entry_id 
     join entry_type et on et.entry_type=e1.entry_type 
     left outer join detail d2 on d2.detail_id=d1.link_detail_id 
     join rep r2 on e1.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where ((d1.detail_type = 'O' and d1.charged_qty<d1.qty and d1.nocharge_qty=0 and e1.entry_type in ('SORD','SRTN') 
     and e1.our_reference not like 'AUTO%') 
     or (d1.detail_type = 'N' and e1.entry_type in('SCRN','DREC','DSRF')) 
     or ((e1.entry_type = 'SJIN') and (d1.total_goods = 0)) 
     or((d1.DETAIL_TYPE = 'N') and (e1.ENTRY_TYPE = 'SINV') and (e1.TAXPOINT_DATE = CURRENT_DATE) and (d2.DETAIL_TYPE = 'A'))) 
     and e1.taxpoint_date=current_date 
     and c2.contact_id=contact_1.contact_id) DAILY_GP, 
    (select count(*) 
     from entry e2 
     join rep r2 on e2.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where e2.entry_type='SORD' 
     and e2.taxpoint_date=current_date 
     and c2.contact_id=contact_1.contact_id) NUM_ORDS, 
    (select count(tn.note) 
     from trader_notes tn join trader t on tn.trader_id=t.trader_id 
     join rep r2 on t.rep_code=r2.rep_code 
     join contact c2 on r2.contact_id=c2.contact_id 
     where tn.created between current_date 
     and (current_date+1) 
     and tn.note_type in ('N','S','G') 
     and tn.note is not null 
     and c2.contact_id=contact_1.contact_id) NOTES 
FROM ENTRY ENTRY_1 INNER JOIN REP REP_1 ON 
    (REP_1.REP_CODE = ENTRY_1.REP_CODE) 
     INNER JOIN CONTACT CONTACT_1 ON 
    (CONTACT_1.CONTACT_ID = REP_1.CONTACT_ID) 
WHERE (ENTRY_1.ENTRY_TYPE = 'SJOB') 
     AND (ENTRY_1.AGE = 0) 

,你可以看到這兩個子程序都是一樣的,唯一不同的是在select語句的總和。有沒有辦法讓我只能運行其中一個子程序來查找總和?

Iv顯示完整的查詢,請問有人能幫我嗎?

+4

哪個數據庫...... SQL-Server,MySQL,Oracle等...... – DRapp 2011-06-09 13:06:45

+0

此外,僅僅從主要集羣加入/子加入來確認,Entry_ID是Entry中的一個自動遞增鍵表,這是直接加入你的「細節」表的「關鍵」(不是你的其他「在哪裏」條件來限定具體細節)......但僅僅是JOIN基礎本身? – DRapp 2011-06-09 13:27:54

+0

Im使用Interbase – c11ada 2011-06-10 10:10:57

回答

1

經過一番評論之後,我想我有些東西要給你射擊......你可能需要調整一些,但希望爲你帶來很多困惑。查詢的最大殺手是你如何得到COUNT(DISTINCT)值不是基於合格條目的主要標準...

這就是說,看着你所有的連接,你從入口表加入到代表表,從代表到聯繫表。如果代表ID總是指向一個聯繫人以獲得相同的「ID」,那麼代表代碼就像銷售人員聯繫人表中實際的「contact_id」的快捷方式。也就是說,不需要加入Rep表或OR表。銷售標題有「REP_CODE」,所以這可以消除所有的連接和分組(除非你糾正我)。

下一步。我有兩個從最內層開始的初步查詢。你最初的OUTERMOST查詢是隻有基於「SJOB」和年齡= 0的條目類型的條目ID。因此,我的「PQ1」(預查詢1)將只獲得那些符合條件並獲得代表代碼的條目,聯繫人ID和姓名,以及相應的年份/時間段。這全是DISTINCT。

這個結果然後基於相同的代表,年份和時間段(因此消除了一堆其他連接/其他位置在哪裏)而加入到條目表(e2別名)中。然後,將e2加入到詳細信息表中以獲取所有項目。這是「PQ2」(預查詢2)的開始。

由於我在給定的聯繫人代表,年份和時間段內收到了不同的結果,因此您似乎正在爲主要PQ1查詢中的任何人獲得整體活動,並在同一合格年份/期限內查看其總體銷售活動。

您爲獲取總額,銷售額和開票金額而獲得的where條款有3個條件。這是PreQuery 2條件的主要「WHERE」子句。在字段列表中,由於它們基本上都具有相同的符合條件,所以我剛添加

SUM(case when ...)as MTD_GP, sum(case when ...)作爲MTD_Sales, 對於Order_GP和Order_Sales(基於FIRST Where部分)的總和() INVOICED_GP和INVOICED_Sales的總和()(基於SECOND Where部分) EXPEND的總和()(基於第三部分(*),count(*))的基礎上,我以THAT結果爲基礎完成所有OTHER計數。等條目。再一次,因爲我知道我已經把它分解成給定的Rep,所以我可以以類似的方式再次重新查詢entry 2表。

希望這能夠很好地闡明我對您試圖完成的查詢的看法,並跳躍式啓動您進入更好/最終解決方案。

從您的聯接中,您的「副表」中有一個聯繫人ID,其中多個代表可以全部指向一個「聯繫人」。沒有必要顯式地加入聯繫人ID,該聯繫人ID已經存在於代表表格中...因此,您可以將聯接簡化爲代表表格的條目表並獲取聯繫人ID。

select 
     PQ2.Rep_Code, 
     PQ2.Contact_ID, 
     PQ2.Name, 
     PQ2.Year_Num, 
     PQ2.Period_Num, 
     PQ2.MTD_GP, 
     PQ2.MTD_SALES, 
     PQ2.ORD_GP, 
     PQ2.ORD_SALE, 
     PQ2.INV_GP, 
     PQ2.INV_SALE, 
     PQ2.EXPEND, 
     (select count(distinct e2.trader_id) 
      from entry e2 
      where e2.rep_code = PQ2.Rep_Code 
       and e2.Year_Num = PQ2.Year_Num 
       and e2.Period_Num = PQ2.Period_Num 
       and e2.entry_type in ('SORD','SINV','DREC')) MTD_PUR, 

     (select count(distinct e2.trader_id) 
      from entry e2 
      where e2.rep_code = PQ2.Rep_Code 
       and e2.Year_Num = PQ2.Year_Num 
       and e2.Period_Num = PQ2.Period_Num 
       and e2.entry_type = 'SORD') MTD_ORD, 

     (select count(*) 
      from entry e2 
      where e2.rep_code = PQ2.Rep_Code 
      and e2.entry_type='SORD' 
      and e2.taxpoint_date = current_date) NUM_ORDS, 


     (select count(tn.note) 
      from trader_notes tn 
       join trader t on tn.trader_id = t.trader_id 
          AND t.rep_code = PQ2.Rep_Code 
      where 
        tn.created between current_date and (current_date + 1) 
       and tn.note_type in ('N','S','G') 
       and tn.note is not null) NOTES, 

     (select 
       sum((d3.total_goods - d3.total_cost) * et3.sign) 
      from 
       entry e3 
       join detail d3 on e3.entry_id = d3.entry_id 
        left join detail dLink on d3.link_detail_id = dLink.detail_id 
       join entry_type et3 on e3.entry_type = et3.entry_type 
      where 
        PQ2.Rep_Code = e3.Rep_Code 
       AND e3.taxpoint_date = current_date 
       AND ( ( d3.detail_type = 'O' 
         and d3.charged_qty < d3.qty 
         and d3.nocharge_qty = 0 
         and e3.entry_type in ('SORD','SRTN') 
         and e3.our_reference not like 'AUTO%' 
        ) 
        or ( d3.detail_type = 'N' 
         and e3.entry_type in ('SCRN','DREC','DSRF') 
        ) 
        or (  e3.entry_type = 'SJIN' 
         and d3.total_goods = 0 
        ) 
        or ( d3.DETAIL_TYPE = 'N' 
         and e3.ENTRY_TYPE = 'SINV' 
         and e3.TAXPOINT_DATE = CURRENT_DATE 
         and dLink.DETAIL_TYPE = 'A' 
        ) 
       ) 
      ) DAILY_GP 

    FROM 
     (select 
       PQ1.Rep_Code, 
       PQ1.Contact_ID, 
       PQ1.Name, 
       PQ1.Year_Num, 
       PQ1.Period_Num, 

       sum((d2.Total_Goods - d2.Total_Cost) * et2.Sign) as MTD_GP, 

       sum(d2.Total_Goods * et2.Sign) as MTD_SALES, 

       sum(case when d2.detail_type = 'O' 
         and d2.charged_qty < d2.qty 
         and d2.nocharge_qty = 0 
         then (d2.total_goods - d2.total_cost) * et2.sign 
         else 0 end) ORD_GP, 

       sum(case when d2.detail_type = 'O' 
         and d2.charged_qty < d2.qty 
         and d2.nocharge_qty = 0 
         then (d2.total_goods * et2.sign) 
         else 0 end) ORD_SALE, 

       sum(case when d2.detail_type = 'N' 
         and e2.entry_type in('SINV','SCRN','DREC','DSRF') 
         then (d2.total_goods - d2.total_cost) * et2.sign 
         else 0 end) INV_GP, 

       sum(case when d2.detail_type = 'N' 
         and e2.entry_type in('SINV','SCRN','DREC','DSRF') 
         then (d2.total_goods * et2.sign) 
         else 0 end) INV_SALE, 

       sum(case when e2.entry_type = 'SJIN' 
         and d2.total_goods = 0 
         then (d2.total_goods - d2.total_cost) * et2.sign 
         else 0 end) EXPEND 

      FROM 
       (select distinct 
         r1.rep_code, 
         r1.contact_id, 
         c1.Name, 
         e1.year_num, 
         e1.period_num 
        from 
         entry e1 
         join rep r1 ON e1.rep_code = r1.rep_code 
          join contact c1 on r1.contact_id = c1.contact_id 
        where 
          e1.entry_type = 'SJOB' 
         and e1.age = 0) PQ1 

       JOIN entry e2 on PQ1.rep_code = e2.rep_code 
          AND PQ1.Year_Num = e2.Year_Num 
          AND PQ1.Period_Num = e2.Period_Num 
        JOIN Detail d2 on e2.Entry_ID = d2.Entry_ID 
        JOIN Entry_Type et2 on e2.entry_type = et2.entry_type 
      WHERE  
       ( d2.detail_type = 'O' 
        and d2.charged_qty < d2.qty 
        and d2.nocharge_qty = 0 ) 

       or ( d2.detail_type = 'N' 
        and e2.entry_type in('SINV','SCRN','DREC','DSRF')) 

       or ( e2.entry_type = 'SJIN' 
        and d2.total_goods = 0) 

      GROUP BY 
       PQ1.Rep_Code, 
       PQ1.Contact_ID, 
       PQ1.Name, 
       PQ1.Year_Num, 
       PQ1.Period_Num) as PQ2 
+0

銷售完成後,該銷售的總體銷售額將存儲在ENTRY表中。然後將其鏈接到存儲該銷售中每個項目的數據的DETAIL表。該入口表也鏈接到存儲哪個銷售代表進行輸入的代表表。 要回答問題DRapp條目ID是唯一標識符鏈接到詳細表 – c11ada 2011-06-10 15:11:05

+1

@ c11ada,張貼複雜的答案,無法測試(顯然),但廣泛澄清如何/爲您發生了什麼。 – DRapp 2011-06-10 16:15:27

+0

我得到以下錯誤,任何想法,爲什麼這可能是即時通訊使用Interbase ibconsole。這可以有不同的sytax? 錯誤位於第1行 動態SQL錯誤 SQL錯誤代碼= -104 令牌未知 - 線75,炭7 選擇 – c11ada 2011-06-13 08:05:40

5

肯定 - 是這樣的:

SELECT ENTRY_1.AGE, ENTRY_1.REP_CODE,CONTACT_1.NAME, ENTRY_1.GOODS, 
      sum((d2.total_goods-d2.total_cost)*et2.sign) 
      , sum((d2.total_goods)*et2.sign) 
. 
. 
. CODE TAKEN OUT 
. 
. 
    FROM 
      detail d2 
      join entry e2 on d2.entry_id=e2.entry_id 
      join entry_type et2 on et2.entry_type=e2.entry_type 
      join rep r2 on e2.rep_code=r2.rep_code 
      join contact c2 on r2.contact_id=c2.contact_id 
      where ((d2.detail_type = 'O' and d2.charged_qty<d2.qty 
      and d2.nocharge_qty=0) 
      or (d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF')) 
      or ((e2.entry_type = 'SJIN') and (d2.total_goods = 0))) 
      and c2.contact_id=contact_1.contact_id 
      and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num))  MTD_GP 
, ENTRY ENTRY_1 INNER JOIN REP REP_1 ON 
     (REP_1.REP_CODE = ENTRY_1.REP_CODE) 
      INNER JOIN CONTACT CONTACT_1 ON 
     (CONTACT_1.CONTACT_ID = REP_1.CONTACT_ID) 
    WHERE (ENTRY_1.ENTRY_TYPE = 'SJOB') 
      AND (ENTRY_1.AGE = 0) 
當然

的想法是,你動下加入下來 - 他們離開SELECT子句,並把它們(一次)到FROM和WHERE子句。 - 我做的剪切和粘貼並不是真的正確,但你明白了(也沒有給出完整的查詢來實際用作基礎)

+0

很好的回答!對於透視而言,解釋爲什麼原始查詢執行得如此糟糕是個好主意。這兩個子查詢是不必要的,但也在select語句本身中,這意味着對於在原始查詢中返回的每一行都執行這兩個子查詢。 – 2011-06-09 13:25:40

+0

Randy ... iv更新了上面的SQL查詢,請你可以建議我如何優化該查詢。 – c11ada 2011-06-10 10:12:33

0

作爲一般規則,你不應該使用相關子查詢任何查詢在數據集最終將大他們的行爲像遊標和運行一行接一行。您應該使用連接到表或派生表。

SQl服務器是這樣的我知道,它可能在其他數據庫中是不同的。