CASE를 사용하여 하나의 SUM보다 여러 COUNT가 더 빠른 이유는 무엇입니까?


14

다음 두 가지 방법 중 어느 것이 더 빠른지 알고 싶었습니다.

1) 세 COUNT:

 SELECT Approved = (SELECT COUNT(*) FROM dbo.Claims d
                  WHERE d.Status = 'Approved'),
        Valid    = (SELECT COUNT(*) FROM dbo.Claims d
                    WHERE d.Status = 'Valid'),
        Reject   = (SELECT COUNT(*) FROM dbo.Claims d
                    WHERE d.Status = 'Reject')

2) -clause SUM와 함께 FROM:

SELECT  Approved = SUM(CASE WHEN Status = 'Approved' THEN 1 ELSE 0 END),
        Valid    = SUM(CASE WHEN Status = 'Valid'    THEN 1 ELSE 0 END),
        Reject   = SUM(CASE WHEN Status = 'Reject'   THEN 1 ELSE 0 END)
FROM dbo.Claims c;

나는 그 차이가 너무 크다고 놀랐다. 세 개의 하위 쿼리가있는 첫 번째 쿼리는 결과를 즉시 반환하지만 두 번째 SUM방법에는 18 초가 필요합니다.

Claims~ 1,800 만 개의 행이 포함 된 테이블에서 선택하는 뷰입니다. FK- 컬럼 ClaimStatus에는 status-name을 포함하는 테이블 에 대한 인덱스 가 있습니다.

왜 내가 사용 여부 등 큰 차이를 만들 않는 COUNTSUM?

실행 계획 :

총 12 개의 상태가 있습니다. 이 세 가지 상태는 모든 행의 7 %에 속합니다.


이것은 실제 견해입니다. 관련이 있는지 확실하지 않습니다.

CREATE VIEW [dbo].[Claims]
AS
SELECT 
   mu.Marketunitname AS MarketUnit, 
   c.Countryname     AS Country, 
   gsp.Gspname       AS GSP, 
   gsp.Wcmskeynumber AS GspNumber, 
   sl.Slname         AS SL, 
   sl.Wcmskeynumber  AS SlNumber, 
   m.Modelname       AS Model, 
   m.Salesname       AS [Model-Salesname], 
   s.Claimstatusname AS [Status], 
   d.Work_order      AS [Work Order], 
   d.Ssn_number      AS IMEI, 
   d.Ssn_out, 
   Remarks, 
   d.Claimnumber     AS [Claim-Number], 
   d.Rma_number      AS [RMA-Number], 
   dbo.ToShortDateString(d.Received_Date, 1) AS [Received Date], 
   Iddata, 
   Fisl, 
   Fimodel, 
   Ficlaimstatus 
FROM Tabdata AS d 
   INNER JOIN Locsl AS sl 
           ON d.Fisl = sl.Idsl 
   INNER JOIN Locgsp AS gsp 
           ON sl.Figsp = gsp.Idgsp 
   INNER JOIN Loccountry AS c 
           ON gsp.Ficountry = c.Idcountry 
   INNER JOIN Locmarketunit AS mu 
           ON c.Fimarketunit = mu.Idmarketunit 
   INNER JOIN Modmodel AS m 
           ON d.Fimodel = m.Idmodel 
   INNER JOIN Dimclaimstatus AS s 
           ON d.Ficlaimstatus = s.Idclaimstatus 
   INNER JOIN Tdefproducttype 
           ON d.Fiproducttype = Tdefproducttype.Idproducttype 
   LEFT OUTER JOIN Tdefservicelevel 
                ON d.Fimaxservicelevel = Tdefservicelevel.Idservicelevel 
   LEFT OUTER JOIN Tdefactioncode AS ac 
                ON d.Fimaxactioncode = ac.Idactioncode 

두 링크 모두 COUNT계획 버전을 가리키는 것 같습니다 . SUM올바른 계획을 가리 키도록 버전에 대해 좋아요를 편집 할 수 있습니까 ?
Geoff Patterson

다른 statii가있는 행과 비교하여이 세 statii이있는 행의 비율은 얼마입니까?
Max Vernon

1
@MaxVernon : 예, 물론 0을 너무 많이 보았습니다. 맞습니다. 내 의견을 삭제하겠습니다. 예, 다른 상태에는 1670 만 개의 행이 있습니다. 대부분은 Authorized입니다.
Tim Schmelter

2
나는 두 번째 계획이 전체 테이블을 12 번 스캔해야한다고 추정합니다 (즉, 보여줍니다). 술어를 스캔으로 푸시 다운하지 못할 가능성이 높습니다. 당신이 추가하면 같은 성능을 무엇 WHERE c.Status = 'Approved' or c.Status = 'Valid' or c.status = 'Reject'받는 SUM변형.
Max Vernon

@MaxVernon : 총 12 개의 상태가 있습니다. 그것은 실제로 나에게 문제가 아니지만 최적화 프로그램이 이것을 처리 할 수 ​​없다는 것이 매우 놀랍습니다. 실행 계획 분석 기술을 연구해야합니다. 대답하십시오. SQL-Server가 세 가지 상태 만 검색 할 수없는 이유는 무엇입니까?
Tim Schmelter

답변:


19

COUNT(*)반면 버전은 한 번 당신이 선택하는 각각의 상태를 단순히 상태 열이 인덱스로 추구 할 수있는 SUM(...)버전의 요구가 인덱스를 열두 번 (독특한 상태 유형의 총 수를) 추구.

인덱스를 세 번 찾는 것은 12 번 찾는 것보다 빠릅니다.

첫 번째 계획에는 238MB의 메모리 부여가 필요한 반면 두 번째 계획에는 650MB의 메모리 부여가 필요합니다. 그것은 더 큰 메모리 부여가 즉시 충전 훨씬 느린 것을 질의을 할 수 없다고합니다.

두 번째 쿼리를 다음과 같이 변경하십시오.

SELECT  Approved = SUM(CASE WHEN Status = 'Approved' THEN 1 ELSE 0 END),
        Valid    = SUM(CASE WHEN Status = 'Valid'    THEN 1 ELSE 0 END),
        Reject   = SUM(CASE WHEN Status = 'Reject'   THEN 1 ELSE 0 END)
FROM dbo.Claims c
WHERE c.Status = 'Approved'
    OR c.Status = 'Valid'
    OR c.Status = 'Reject';

이를 통해 쿼리 최적화 프로그램은 인덱스 탐색의 75 %를 제거 할 수 있으며 필요한 메모리 부여가 줄어들고 I / O 요구 사항이 줄어들며 결과 시간이 단축됩니다.

SUM(CASE WHEN ...)구조는 쿼리 최적화 프로그램이 Status술어를 계획의 인덱스 탐색 부분으로 푸시 다운 하는 것을 본질적으로 방지합니다 .


기억력이 좋았습니다. 내 32GB가 모두 현재 사용중인 것으로 나타났습니다 (300MB 만 사용 가능). 편집 그러나 일부 메모리를 확보했습니다. 결과는 동일합니다
Tim Schmelter

max server memory옵션 을보고 싶을 수도 있습니다. 시스템에 맞는 올바른 값으로 구성해야합니다. 이를 수행하는 방법에 대한 자세한 내용 은 질문과 답변을 참조하십시오.
Max Vernon

1
불행하게도이 서버는 데이터베이스뿐만 아니라 SSAS 큐브 및 일부 도구 (인트라넷 웹앱 포함)에도 사용됩니다. 그러나 이미 최대 12GB를 할당했습니다.
Tim Schmelter
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.