2013-07-22 4 views
0

이 쿼리는 평균 4 초가 소요됩니다. 저장 프로 시저에서 하위 쿼리가 될 것이므로 잠시 초를 필요로합니다. 다음은 쿼리입니다 :SQL Server -이 쿼리를 어떻게 최적화 할 수 있습니까?

(select customercampaignname + ' $' + convert(varchar, cast(amount as numeric(36,2))) As 'Check_Stub_Comment2' from (
    select ROW_NUMBER() OVER (ORDER BY amount desc) as rownumber, customercampaignname, amount from (
     select * from (
       select distinct d.customercampaignname 
        ,sum(d.mastercurrencyamount) As amount 

       from bb02_donation d 
         JOIN bb02_donationline dl on d.donationid = dl.donationid 
         JOIN bb02_fundraiserrevenuestream frs on dl.fundraiserrevenuestreamid = frs.fundraiserrevenuestreamid and frs.fundraiserid = 1869 

       where d.customercampaignname is not null 
         and d.customercampaignname != '' 
       group by d.CustomerCampaignName 
     ) as x 
) as sub) as y where rownumber = 1) 
+0

- "rownumber ="가 중요합니다. 나는 오직 1 행만을 선택하거나 2 행만을 배정 할 수 있어야한다. – Induster

+0

아래에 표시된 대답은이 쿼리를 더 빠르게 만들지 만 여전히 데이터베이스에 대한 n + 호출입니다. 필자의 경우에는 2 개의 결과에만 관심이 있으므로 데이터베이스에 한 번만 호출하면 임시 테이블에 저장됩니다. 그런 다음 상위 1 개 결과를 가져 와서 정렬하고 임시 테이블에서 상위 1 개 결과를 다시 가져올 수있었습니다. 이로 인해 총 쿼리 시간이 절반으로 줄었습니다. 답변 해 주셔서 감사합니다. – Induster

답변

0

행 번호를 실제로 사용할 필요가없는 경우 TOP 1 행을 가져옵니다. 쿼리가 많이 단순화 될 수 있습니다. 나는 먼저 당신의 술어에 의해 가장 많이 걸러 질 테이블을 선택하는 것으로 시작하고 싶다. frs.fundraiserid와 조인에 참여하는 모든 열에 대한 좋은 인덱스가 있기를 바랍니다.

SELECT 
TOP 2 customercampaignname + ' $' + CONVERT(VARCHAR(255), CAST(SUM(d.mastercurrencyamount) AS NUMERIC(36,2))) AS 'Check_Stub_Comment2', 
ROW_NUMBER() OVER(ORDER BY SUM(d.mastercurrencyamount) DESC) as rownumber 
FROM bb02_fundraiserrevenuestream frs 
JOIN bb02_donationline dl ON 
dl.fundraiserrevenuestreamid = frs.fundraiserrevenuestreamid 
JOIN bb02_donation d ON 
d.donationid = dl.donationid   
WHERE frs.fundraiserid = 1869 
AND d.customercampaignname IS NOT NULL 
AND d.customercampaignname != '' 
GROUP BY d.CustomerCampaignName 
ORDER BY SUM(d.mastercurrencyamount) DESC 

첫 번째 행 또는 두 번째 행을 선택할 수 있어야하므로 CTE 또는 하위 쿼리로 줄 바꿈해야합니다.

WITH topcampaign AS (
SELECT 
TOP 2 customercampaignname + ' $' + CONVERT(varchar(255), CAST(SUM(d.mastercurrencyamount) AS NUMERIC(36,2))) AS 'Check_Stub_Comment2', 
ROW_NUMBER() OVER(ORDER BY SUM(d.mastercurrencyamount) DESC) as rownumber 
FROM bb02_fundraiserrevenuestream frs 
JOIN bb02_donationline dl ON 
dl.fundraiserrevenuestreamid = frs.fundraiserrevenuestreamid 
JOIN bb02_donation d ON 
d.donationid = dl.donationid   
WHERE frs.fundraiserid = 1869 
AND d.customercampaignname IS NOT NULL 
AND d.customercampaignname != '' 
GROUP BY d.CustomerCampaignName 
ORDER BY SUM(d.mastercurrencyamount) DESC 
) 
SELECT * from topcampaign WHERE rownumber = 1 

또 다른 가능한 최적화로서, 나는 CTE에서 CONVERT를 가져 와서 최종 선택에 넣었습니다. 그것이 많은 도움이되는지 확실하지 않습니다.

WITH topcampaign AS (
SELECT 
TOP 2 
customercampaignname, 
SUM(d.mastercurrencyamount) AS amount, 
ROW_NUMBER() OVER(ORDER BY SUM(d.mastercurrencyamount) DESC) as rownumber 
FROM bb02_fundraiserrevenuestream frs 
JOIN bb02_donationline dl ON 
dl.fundraiserrevenuestreamid = frs.fundraiserrevenuestreamid 
JOIN bb02_donation d ON 
d.donationid = dl.donationid   
WHERE frs.fundraiserid = 1869 
AND d.customercampaignname IS NOT NULL 
AND d.customercampaignname != '' 
GROUP BY 
d.CustomerCampaignName 
ORDER BY 
SUM(d.mastercurrencyamount) DESC 
) 
SELECT 
rownumber, 
customercampaignname + ' $' + CONVERT(varchar(255), CAST(amount AS NUMERIC(36,2))) AS 'Check_Stub_Comment2' 
FROM topcampaign 
WHERE rownumber = 1 
+0

감사합니다. 실제로 행 번호가 필요하므로 1 행 또는 2 행 중 하나를 선택할 수 있습니다. Top 1이 작동하지만 두 번째 행을 쿼리하는 방법이 필요합니다. – Induster

+0

나는 내 대답을 편집하여 ROW_NUMBER를 출력에 추가했습니다. TOP를 TOP N으로 변경할 수 있습니다. 여기서 N은 유효한 정수입니다. 그래서 상위 2 만 필요하고 rownumber가 필요한 경우 TOP 2로 변경하십시오. –

+0

다시 설명 드리겠습니다. 행 1을 리턴하거나 행 2를 독점적으로 리턴해야합니다. 그래서, "where rownumber = 2"라고 말하고 결과 세트에서 2 행만 가져와야합니다. 난 지금 당신의 SQL 위의 일이 있도록 노력하고있어. – Induster

0

이 빠르게 실행한다면 모르겠지만, 내 계산으로이 단순화 될 수있다

Select top 1 customercampaignname + ' $' + convert(varchar(255), cast(sum(d.mastercurrencyamount) as numeric(36,2))) As amount 
from bb02_donation d JOIN 
    bb02_donationline dl 
    on d.donationid = dl.donationid JOIN 
    bb02_fundraiserrevenuestream frs 
    on dl.fundraiserrevenuestreamid = frs.fundraiserrevenuestreamid and frs.fundraiserid = 1869 
where d.customercampaignname is not null and d.customercampaignname != '' 
group by d.CustomerCampaignName 
order by sum(d.mastercurrencyamount) 
0

이 하나를 취하면 나도 몰라 차이

;WITH cte AS 
(
    select *, ROW_NUMBER() OVER (ORDER BY amount desc) as rownumber 
    from (
     select distinct d.customercampaignname, sum(d.mastercurrencyamount) As amount 
     from bb02_donation d 
     INNER JOIN bb02_donationline dl on d.donationid = dl.donationid 
     INNER JOIN bb02_fundraiserrevenuestream frs on dl.fundraiserrevenuestreamid = frs.fundraiserrevenuestreamid and frs.fundraiserid = 1869 
     where d.customercampaignname is not null 
       and d.customercampaignname != '' 
     group by d.CustomerCampaignName 
    ) as x 
) 
SELECT TOP 1 * 
FROM cte 
ORDER BY RowNumber 

테이블이 당신을 아주 예를 들어, 일을 필터링하기 위해해야 ​​할 경우, 쿼리의 나머지 부분을 할 경우에만 bb02_fundraiserrevenuestream.fundraiserid = 1869 다음 선택할 수 있습니다. 잘 모르겠다. 실행 계획을 시도하고 검토하는 문제 일 수 있습니다.

;WITH Frs AS 
(SELECT dl.fundraiserrevenuestreamid 
    FROM bb02_fundraiserrevenuestream 
    WHERE fundraiserid = 1869 
) 
, cte AS (
    select d.customercampaignname, sum(d.mastercurrencyamount) As amount 
    from Frs 
    INNER JOIN bb02_donationline dl ON dl.fundraiserrevenuestreamid = frs.fundraiserrevenuestreamid 
    INNER JOIN bb02_donation d on d.donationid = dl.donationid 
    where d.customercampaignname is not null 
      and d.customercampaignname != '' 
    group by d.CustomerCampaignName 
) 
SELECT TOP 1 customercampaignname + ' $' + convert(varchar, cast(amount as numeric(36,2))) As 'Check_Stub_Comment2' 
FROM cte 
ORDER BY sum(d.mastercurrencyamount) 

항상 그렇듯이 INDEXES은 이러한 성능 문제의 해결책이 될 수 있습니다.

관련 문제