다음 두 가지 방법 중 어느 것이 더 빠른지 알고 싶었습니다.
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을 포함하는 테이블 에 대한 인덱스 가 있습니다.
왜 내가 사용 여부 등 큰 차이를 만들 않는 COUNT
나 SUM
?
실행 계획 :
총 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(...)
버전의 요구가 인덱스를 열두 번 (독특한 상태 유형의 총 수를) 추구.
인덱스를 세 번 찾는 것은 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
술어를 계획의 인덱스 탐색 부분으로 푸시 다운 하는 것을 본질적으로 방지합니다 .