2014-12-05 197 views
1

我有一個查詢運行了12個小時。優化SQL Server 2012查詢

查詢並留下聯接5個表和報告一堆月度指標。下面是該查詢:

SELECT DATEPART(YYYY,Referral_dt) AS RefYear, DATEPART(MM,Referral_dt) AS RefMonth, 
     CASE 
      WHEN CAST(Referral_dt as date) BETWEEN '1/1/2013' AND '4/14/2013' THEN 'Q1' 
      WHEN CAST(Referral_dt as date) BETWEEN '4/15/2013' AND '7/14/2013' THEN 'Q2' 
      WHEN CAST(Referral_dt as date) BETWEEN '7/15/2013' AND '9/30/2013' THEN 'Q3' 
      WHEN CAST(Referral_dt as date) BETWEEN '10/1/2013' AND '12/31/2013' THEN 'Q4' 
      WHEN CAST(Referral_dt as date) BETWEEN '1/1/2014' AND '4/14/2014' THEN 'Q1' 
      WHEN CAST(Referral_dt as date) BETWEEN '4/15/2014' AND '7/14/2014' THEN 'Q2' 
      WHEN CAST(Referral_dt as date) BETWEEN '7/15/2014' AND '9/30/2014' THEN 'Q3' 
      WHEN CAST(Referral_dt as date) BETWEEN '10/1/2014' AND '12/31/2014' THEN 'Q4' 
     ELSE 'X' END as RefQtr, 
     crm.salesstatuscode, crm.Referral_State, crm.lead_source, mp.mcc_desc, mp.mcc_industry, sr.manager_name, sr.payrollname, 
     sr.region as Sales_Region,sr.market as Sales_Market, sr.saleschannel as SalesChannel, Bk.SuperRegion_Name as Bank_SuperRegion, 
     Bk.Region_Name as Bank_Region ,Bk.Division_Name as Bank_Division, 
     sum(case when crm.referral_state = 'Won' then 1 else 0 end) as referrals_won, sum(sv.projected_profit) as prj_profit, 
     sum(case when mp.proposal_Date is null then 0 else 1 end) as proposals_created, sum(ac.signed_annual_volume) as total_signed_volume, 
     sum(case when ac.Acct_Act_Date is null then 0 else 1 end) as activated_accounts, COUNT(*) as referral_count 
     into moagg1 
FROM kaiserver.dbKAI.dbo.Referrals_CRM CRM 
    LEFT JOIN (SELECT p.merchant_id, CAST(p.proposal_create_dt as date) as Proposal_Date, m.mcc_desc, m.mcc_industry 
       from kaiserver.[dbKAI].[dbo].[proposals] p 
       left join (SELECT mcc, mcc_desc, mcc_industry from kaiserver.[dbKAI].[dbo].[merchantcategorycode]) m 
       on p.mcc = m.mcc where datepart(yyyy,proposal_create_dt) in ('2013', '2014')) mp 
     ON crm.merchant_id = mp.merchant_id 
    LEFT JOIN (SELECT account_no, CAST(Account_Activate_dt as date) as Acct_Act_Date, signed_annual_volume, average_tkt 
       from kaiserver.[dbKAI].[dbo].[Account] 
       where current_ind=1 and datepart(yyyy,account_submit_dt) in ('2013', '2014')) ac 
    ON crm.account_no = ac.account_no 
    LEFT JOIN (SELECT e1.repid, e1.repcode, e1.payrollname, e1.salesmanager, e2.payrollname as manager_name, 
      e1.region,e1.market, e1.saleschannel 
      FROM [fdserver].fdms.[dbo].[tbl_reps] e1 LEFT JOIN [fdserver].fdms.[dbo].[tbl_reps] e2 
        ON e1.salesmanager = e2.repid 
      WHERE e1.market not like ('%TEST%') and e1.payrollname is not null and e1.region is not null and e1.market is not null) SR 
    ON CRM.Sales_Rep_Cd = SR.Repcode 
    LEFT JOIN (SELECT [AU_name], [AU_Code] ,[SuperRegion_Name], [Region_Name] ,[Division_Name], 
        [SubDivision_Name] ,[District_Name] ,[SubDistrict_Name] 
      FROM kaiserver.[dbKAI].[dbo].[BankAU_Hierarchy] 
      WHERE [Reporting_Interval_Id] = '201410') BK 
    ON CRM.referral_au = BK.AU_code 
    LEFT JOIN (select merchantnumber, projected_profit from kaiserver.[dbKAI].[dbo].[SoldVolumeDetail]) sv 
    ON crm.account_no = sv.merchantnumber 
    WHERE DATEPART(YYYY, Referral_dt) in ('2013', '2014') 
      AND (crm.salesstatuscode <> 'DUPL' or crm.salesstatuscode is null) 
      AND crm.lead_source not in ('Test Lead', 'Bank Lead Placeholder') 
    group by DATEPART(YYYY,Referral_dt), DATEPART(MM,Referral_dt), crm.Referral_State, crm.salesstatuscode, crm.lead_source, mp.mcc_desc, 
    mp.mcc_industry, sr.manager_name, sr.payrollname, sr.region,sr.market, sr.saleschannel, Bk.SuperRegion_Name, Bk.Region_Name ,Bk.Division_Name, 
    CASE 
     WHEN CAST(Referral_dt as date) BETWEEN '1/1/2013' AND '4/14/2013' THEN 'Q1' 
     WHEN CAST(Referral_dt as date) BETWEEN '4/15/2013' AND '7/14/2013' THEN 'Q2' 
     WHEN CAST(Referral_dt as date) BETWEEN '7/15/2013' AND '9/30/2013' THEN 'Q3' 
     WHEN CAST(Referral_dt as date) BETWEEN '10/1/2013' AND '12/31/2013' THEN 'Q4' 
     WHEN CAST(Referral_dt as date) BETWEEN '1/1/2014' AND '4/14/2014' THEN 'Q1' 
     WHEN CAST(Referral_dt as date) BETWEEN '4/15/2014' AND '7/14/2014' THEN 'Q2' 
     WHEN CAST(Referral_dt as date) BETWEEN '7/15/2014' AND '9/30/2014' THEN 'Q3' 
     WHEN CAST(Referral_dt as date) BETWEEN '10/1/2014' AND '12/31/2014' THEN 'Q4' 
    ELSE 'X' END 

當我運行了完整的查詢如上,運行12小時。但是當我運行查詢1個月時,它運行8分鐘。所以我想運行每個月的查詢並追加到一個文件中。這應該使這個查詢在2-3小時內運行。

我可以使用union並複製代碼24次,但這似乎並不是最好的方式。有沒有更好的方法來做到這一點?

更新:我希望能夠每天運行此查詢來更新最新月份的數字。

+0

請發佈您的執行計劃。 – 2014-12-05 18:26:10

+0

我可以在每個月的月份= 1和年份= 2013年工會全部選擇....月份= 2和年份= 2013年工會所有...'等。那是你執行計劃的意思嗎? – Moosa 2014-12-05 18:32:12

+2

不,不是。谷歌「SQL Server執行計劃」 – 2014-12-05 18:34:49

回答

1

通過你貼我想你已經丟失的連接謂詞,併產生一噸的中間行的執行計劃的外觀:

query plan

這裏稍微清理了同樣的查詢( CTE而不是相關的子查詢,並用DATEPART(QUARTER)取代CASE語句),它可能會更容易地判斷您的缺失謂詞的位置:

WITH 
m as (SELECT mcc, mcc_desc, mcc_industry from kaiserver.[dbKAI].[dbo].[merchantcategorycode]), 
mp as (SELECT p.merchant_id, CAST(p.proposal_create_dt as date) as Proposal_Date, m.mcc_desc, m.mcc_industry 
    from kaiserver.[dbKAI].[dbo].[proposals] p 
    left join m on p.mcc = m.mcc where datepart(yyyy,proposal_create_dt) in ('2013', '2014')), 
ac as (SELECT account_no, CAST(Account_Activate_dt as date) as Acct_Act_Date, signed_annual_volume, average_tkt 
    from kaiserver.[dbKAI].[dbo].[Account] 
    where current_ind=1 and datepart(yyyy,account_submit_dt) in ('2013', '2014')), 
sr as (SELECT e1.repid, e1.repcode, e1.payrollname, e1.salesmanager, e2.payrollname as manager_name, e1.region,e1.market, e1.saleschannel 
    FROM [fdserver].fdms.[dbo].[tbl_reps] e1 
    LEFT JOIN [fdserver].fdms.[dbo].[tbl_reps] e2 ON e1.salesmanager = e2.repid 
    WHERE e1.market not like ('%TEST%') and e1.payrollname is not null and e1.region is not null and e1.market is not null), 
bk as (SELECT [AU_name], [AU_Code], [SuperRegion_Name], [Region_Name] ,[Division_Name], [SubDivision_Name], [District_Name], [SubDistrict_Name] 
    FROM kaiserver.[dbKAI].[dbo].[BankAU_Hierarchy] 
    WHERE [Reporting_Interval_Id] = '201410'), 
sv as (select merchantnumber, projected_profit from kaiserver.[dbKAI].[dbo].[SoldVolumeDetail]) 

SELECT DATEPART(YYYY,Referral_dt) AS RefYear, DATEPART(MM,Referral_dt) AS RefMonth, DATEPART(QUARTER, Referral_dt) as RefQtr, 
    crm.salesstatuscode, crm.Referral_State, crm.lead_source, mp.mcc_desc, mp.mcc_industry, sr.manager_name, sr.payrollname, 
    sr.region as Sales_Region,sr.market as Sales_Market, sr.saleschannel as SalesChannel, Bk.SuperRegion_Name as Bank_SuperRegion, 
    Bk.Region_Name as Bank_Region ,Bk.Division_Name as Bank_Division, 
    sum(case when crm.referral_state = 'Won' then 1 else 0 end) as referrals_won, sum(sv.projected_profit) as prj_profit, 
    sum(case when mp.proposal_Date is null then 0 else 1 end) as proposals_created, sum(ac.signed_annual_volume) as total_signed_volume, 
    sum(case when ac.Acct_Act_Date is null then 0 else 1 end) as activated_accounts, COUNT(*) as referral_count INTO moagg1 
FROM kaiserver.dbKAI.dbo.Referrals_CRM CRM 
LEFT JOIN mp ON crm.merchant_id = mp.merchant_id 
LEFT JOIN ac ON crm.account_no = ac.account_no 
LEFT JOIN sr ON crm.sales_rep_cd = sr.repcode 
LEFT JOIN bk ON crm.referral_au = ck.au_code 
LEFT JOIN sv ON crm.account_no = sv.merchantnumber 

WHERE DATEPART(YYYY, Referral_dt) in ('2013', '2014') 
    AND (crm.salesstatuscode <> 'DUPL' or crm.salesstatuscode is null) 
    AND crm.lead_source not in ('Test Lead', 'Bank Lead Placeholder') 

group by DATEPART(YYYY,Referral_dt), DATEPART(MM,Referral_dt), crm.Referral_State, crm.salesstatuscode, crm.lead_source, mp.mcc_desc, 
    mp.mcc_industry, sr.manager_name, sr.payrollname, sr.region,sr.market, sr.saleschannel, Bk.SuperRegion_Name, Bk.Region_Name ,Bk.Division_Name, 
    DATEPART(QUARTER, Referral_dt) 
+0

謝謝,我應該找什麼? – Moosa 2014-12-05 19:53:45

+0

@Moosa任何加入其中條件可以選擇更多的記錄比預期的,如:crm.referrals_au = ck.au_code採用121M和30K和生產360B - 如果這是高可能是與匹配au_code幾個不同的記錄被交加入。要消除它們,您需要爲連接提供其他條件。 – gordy 2014-12-05 20:06:43

+0

對於上下文,AU是商店。在您給出的AU示例中,crm表在AU級別具有AU的銷售,AU表具有AU名稱。因此crm具有AU代碼多重時間,並且聯接是交叉聯接。你是這個意思嗎?即如果一個AU在CRM中有100條記錄,那麼它會進行100次連接,對吧?那導致了糟糕的表現?如果是這樣,我將如何重寫該連接? – Moosa 2014-12-05 20:28:20

0

我認爲這會產生相同的輸出,它應該會更快。此外,您需要確保用於JOIN或WHERE子句中的每個字段都已編入索引。

SELECT 
    DATEPART(YYYY,Referral_dt) AS RefYear, DATEPART(MM,Referral_dt) AS RefMonth, 
    CASE 
     WHEN CAST(Referral_dt as date) BETWEEN '1/1/2013' AND '4/14/2013' THEN 'Q1' 
     WHEN CAST(Referral_dt as date) BETWEEN '4/15/2013' AND '7/14/2013' THEN 'Q2' 
     WHEN CAST(Referral_dt as date) BETWEEN '7/15/2013' AND '9/30/2013' THEN 'Q3' 
     WHEN CAST(Referral_dt as date) BETWEEN '10/1/2013' AND '12/31/2013' THEN 'Q4' 
     WHEN CAST(Referral_dt as date) BETWEEN '1/1/2014' AND '4/14/2014' THEN 'Q1' 
     WHEN CAST(Referral_dt as date) BETWEEN '4/15/2014' AND '7/14/2014' THEN 'Q2' 
     WHEN CAST(Referral_dt as date) BETWEEN '7/15/2014' AND '9/30/2014' THEN 'Q3' 
     WHEN CAST(Referral_dt as date) BETWEEN '10/1/2014' AND '12/31/2014' THEN 'Q4' 
    ELSE 'X' END as RefQtr, 
    crm.salesstatuscode, crm.Referral_State, crm.lead_source, m.mcc_desc, m.mcc_industry, e2.manager_name, e1.payrollname, 
    e1.region as Sales_Region,e1.market as Sales_Market, e1.saleschannel as SalesChannel, Bk.SuperRegion_Name as Bank_SuperRegion, 
    Bk.Region_Name as Bank_Region ,Bk.Division_Name as Bank_Division, 
    sum(case when crm.referral_state = 'Won' then 1 else 0 end) as referrals_won, sum(sv.projected_profit) as prj_profit, 
    sum(case when p.proposal_Date is null then 0 else 1 end) as proposals_created, sum(ac.signed_annual_volume) as total_signed_volume, 
    sum(case when ac.Acct_Act_Date is null then 0 else 1 end) as activated_accounts, COUNT(*) as referral_count 
into moagg1 
FROM kaiserver.dbKAI.dbo.Referrals_CRM CRM 
LEFT kaiserver.[dbKAI].[dbo].[proposals] p ON crm.merchant_id = p.merchant_id 
    AND datepart(yyyy,p.proposal_create_dt) in ('2013', '2014') 
left join kaiserver.[dbKAI].[dbo].[merchantcategorycode] m on p.mcc = m.mcc 
LEFT JOIN kaiserver.[dbKAI].[dbo].[Account] ac ON crm.account_no = ac.account_no 
    AND ac.current_ind=1 
    AND and datepart(yyyy,ac.account_submit_dt) in ('2013', '2014') 
LEFT JOIN [fdserver].fdms.[dbo].[tbl_reps] e1 ON e1.repcode=CRM.Sales_Rep_Cd 
    AND e1.market not like ('%TEST%') 
    and e1.payrollname is not null 
    and e1.region is not null 
    and e1.market is not null 
LEFT JOIN [fdserver].fdms.[dbo].[tbl_reps] e2 ON e1.salesmanager = e2.repid 
LEFT JOIN kaiserver.[dbKAI].[dbo].[BankAU_Hierarchy] BK ON CRM.referral_au = BK.AU_code 
    AND [Reporting_Interval_Id] = '201410' 
LEFT JOIN kaiserver.[dbKAI].[dbo].[SoldVolumeDetail] sv ON crm.account_no = sv.merchantnumber 
WHERE DATEPART(YYYY, CRM.Referral_dt) in ('2013', '2014') 
AND ISNULL(crm.salesstatuscode,'') <> 'DUPL' 
AND crm.lead_source not in ('Test Lead', 'Bank Lead Placeholder') 
group by DATEPART(YYYY,Referral_dt), DATEPART(MM,Referral_dt), crm.Referral_State, crm.salesstatuscode, crm.lead_source, mp.mcc_desc, 
    mp.mcc_industry, sr.manager_name, sr.payrollname, sr.region,sr.market, sr.saleschannel, Bk.SuperRegion_Name, Bk.Region_Name ,Bk.Division_Name, 
    CASE 
     WHEN CAST(Referral_dt as date) BETWEEN '1/1/2013' AND '4/14/2013' THEN 'Q1' 
     WHEN CAST(Referral_dt as date) BETWEEN '4/15/2013' AND '7/14/2013' THEN 'Q2' 
     WHEN CAST(Referral_dt as date) BETWEEN '7/15/2013' AND '9/30/2013' THEN 'Q3' 
     WHEN CAST(Referral_dt as date) BETWEEN '10/1/2013' AND '12/31/2013' THEN 'Q4' 
     WHEN CAST(Referral_dt as date) BETWEEN '1/1/2014' AND '4/14/2014' THEN 'Q1' 
     WHEN CAST(Referral_dt as date) BETWEEN '4/15/2014' AND '7/14/2014' THEN 'Q2' 
     WHEN CAST(Referral_dt as date) BETWEEN '7/15/2014' AND '9/30/2014' THEN 'Q3' 
     WHEN CAST(Referral_dt as date) BETWEEN '10/1/2014' AND '12/31/2014' THEN 'Q4' 
    ELSE 'X' END 
+0

感謝但分裂了e1和e2連接不起作用,因爲這是一個員工表,我需要進行自我連接以獲取每個員工的經理姓名。我需要鼓搗這個來測試......由於連接的分裂,在select和group by子句中還有別名命名錯誤。 – Moosa 2014-12-05 19:31:47

+0

@莫薩基於原始的SQL,我沒有看到員工的自我加入。對不起,如果我錯過任何別名,我想我得到了他們所有的重構。 – UnhandledExcepSean 2014-12-05 20:06:29