2014-12-05 3 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

실행 계획을 게시하십시오. –

+0

내가 할 수있는 것은'선택 .... 월 = 1 년 = 2013 년 조합 모두 선택 .... 어디 = 2 년 = 2013 년 조합 모두 ... '등. 그게 당신이 처형 계획의 의미였습니까? – Moosa

+2

아니야. Google "SQL Server 실행 계획" –

답변

1

: 여기

query plan

약간 청소 같은 쿼리 (상관 관계가있는 하위 쿼리 대신 CTE를 사용하고 CASE 문을 DATEPART (QUARTER)로 바꾼 경우 누락 된 조건 자의 위치를 ​​쉽게 알 수 있습니다.

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

+0

@Moosa 조건이 예상보다 많은 레코드를 선택하는 조건 인 경우, 예 : crm.referrals_au = ck.au_code는 121M과 30K를 사용하고 360B를 생성합니다. 일치하는 au_code가있는 여러 레코드가 교차 될 수 있습니다 합류했다. 이를 제거하려면 조인에 대한 추가 기준을 제공해야합니다. – gordy

+0

컨텍스트의 경우 AU는 상점입니다.당신이 준 예제에서 crm 테이블은 트랜잭션 레벨에서 AU에 의한 판매를 가지고 있고 AU 테이블은 AU 네임을 가지고 있습니다. 그래서 crm은 AU 코드를 여러 번 가지고 있으며 조인은 크로스 조인입니다. 너가 말하는게 이거니? 즉, AU에 CRM에 100 개의 레코드가있는 경우 100 개의 조인을 수행하고 있습니까? 그리고 그게 성능 저하의 원인입니까? 그렇다면 어떻게 그 조인을 다시 작성합니까? – Moosa

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

+0

@Moosa 원래 SQL을 기반으로, 나는 직원을위한 자체 조인을 보지 않을 것이다. 죄송합니다. 별칭을 놓친 경우 리팩토링 한대로 모든 것을 알았습니다. – UnhandledExcepSean