2016-10-19 6 views
4

쿼리 설명을하고 다음 COUNT (PersonID로 식별)COUNT (1) + (DISTINCT()) 훨씬 느린 2 개 쿼리를 별도로

  • Person은 (JobID로 식별) Job 대응이 있거나 없을 수 있습니다.
  • 해당하는 Job이있는 경우 바인딩은 PersonJob (PersonID < =>JobID) 테이블에 저장됩니다.
  • PersonJob이 없으면 무시됩니다.
  • JobCityID입니다.

    SELECT 
        Job.CityID, COUNT(1) NumTotal, COUNT(DISTINCT(Person.HouseID)) NumDistinct 
    FROM 
        Job 
        INNER JOIN PersonJob ON (PersonJob.JobID = Job.JobID) 
        INNER JOIN Person ON (Person.PersonID = PersonJob.PersonID) 
    GROUP BY 
        Job.CityID 
    

    통계 :

    • SELECT COUNT(1) FROM PersonJob ~ 600.000
    • 모든 Job.CityID
    • 는 쿼리 Person의 총 수를 알고도 독특한 Person.HouseID

    쿼리의 계산 싶어 SELECT COUNT(1) FROM Person ~ 800.000

  • SELECT COUNT(DISTINCT(Person.HouseID)) FROM Person ~ 10.000
  • SELECT COUNT(1) FROM Job ~ 500
  • MS SQL 서버 10.50

문제 : 쿼리 별도로 실행할 때, 0.25sec에서 실행의

  • COUNT(1) 부분. 별도로 실행할 때 쿼리의

    SELECT 
        Job.CityID, COUNT(1) NumTotal 
    FROM 
        Job 
        INNER JOIN PersonJob ON (PersonJob.JobID = Job.JobID) 
        INNER JOIN Person ON (Person.PersonID = PersonJob.PersonID) 
    GROUP BY 
        Job.CityID 
    
  • COUNT(DISTINCT(Person.HouseID)) 부분은, 0.80sec에서 실행됩니다. 3 배 느린 이유 -

    SELECT 
        Job.CityID, COUNT(DISTINCT(Person.HouseID)) NumDistinct 
    FROM 
        Job 
        INNER JOIN PersonJob ON (PersonJob.JobID = Job.JobID) 
        INNER JOIN Person ON (Person.PersonID = PersonJob.PersonID) 
    GROUP BY 
        Job.CityID 
    
  • 전체 쿼리는 3.10sec에서 실행?

실행 계획 :

  • 내가 그 읽기에 어떤 전문가는 아니지만, 죄송합니다.(
    • 25 % 해시 일치 (집계) (출력 Job.CityID)
    • 15 % 해시 일치 내부를 :
    • 는 지금까지 내가 말할 수있는 문제가 일부 쿼리에서
    • (DISTINCT) COUNT 내에있는 (출력
    • 14 % 지수가 추구 (출력 Job.CityID, Person.HouseID)
      • 30 % 인덱스 스캔 (출력 Person.PersonID, Person.HouseID)) 가입 PersonJob.PersonID)
    • 전체 쿼리에서
  • :
    • 03퍼센트 해시 매치 (부분 집합) (출력 Job.CityID, COUNT(*))
    • 31 % 해시 일치 (집계) (출력 Job.CityID)
    • 29 % 테이블 스풀 (출력 Job.CityID, Person.HouseID)
  • ,
+0

비교 작업에'join's을 사용합니까? –

+0

어쩌면 부분 쿼리 일까? 그들을 추가했습니다. – Codeguard

+0

관련 없음, 그러나 :'distinct'는 *** NOT *** 함수입니다. 'distinct (Person.HouseID)'는 ** 정확히 ** distinct Person.HouseID'와 동일합니다. –

답변

4

이 SQL Server 버전에서 알려진 문제는 당신은 on the code here 기반이 재 작성을 시도해 볼 수도 이전에 2012 년

이다.

WITH T1 
    AS (SELECT Job.CityID, 
       Person.HouseID 
     FROM Job 
       INNER JOIN PersonJob 
         ON (PersonJob.JobID = Job.JobID) 
       INNER JOIN Person 
         ON (Person.PersonID = PersonJob.PersonID)), 
    PartialSums 
    AS (SELECT COUNT(*) AS CountStarPartialCount, 
       HouseID, 
       CityID 
     FROM T1 
     GROUP BY CityID, 
        HouseID) 
SELECT CityID, 
     SUM(CountStarPartialCount) AS NumTotal, 
     COUNT(HouseID)    AS NumDistinct 
FROM PartialSums 
GROUP BY CityID 

SQL Server 2012에는이 영역이 약간 개선되었습니다. Is Distinct Aggregation Still Considered Harmful?

+2

최적화 의이 독특한 생각하지 마십시오. 나는 오늘 새로운 것을 배웠다. 고맙습니다. –

+0

감사합니다. 적어도 그것은 MS SQL의 문제점이라는 것을 알고 있습니다. 나는 최종 결정을 별도의 답변으로 게시했다. – Codeguard

1

Martin Smith가 제공 한 해결 방법을 읽은 후에는 해결 방법이 너무 이해하기 어려워서 DISTINCT 열이 추가적으로 필요하다는 판단이 들었습니다. 나는 다음과 같은 부분 쿼리를 가입 LEFT하기로 결정했습니다 : "해결 방법"SQL은 0.60sec에서 실행되는 동안

SELECT 
    Job.CityID, NumTotal.Value, NumDistinct.Value 
FROM 
    Job 
    LEFT JOIN 
    (
    SELECT 
     Job.CityID, COUNT(1) AS Value 
    FROM 
     Job 
     INNER JOIN PersonJob ON (PersonJob.JobID = Job.JobID) 
     INNER JOIN Person ON (Person.PersonID = PersonJob.PersonID) 
    GROUP BY 
     Job.CityID 
) NumTotal ON (NumTotal.CityID = Job.CityID) 
    LEFT JOIN 
    (
    SELECT 
     Job.CityID, COUNT(DISTINCT Person.HouseID) AS Value 
    FROM 
     Job 
     INNER JOIN PersonJob ON (PersonJob.JobID = Job.JobID) 
     INNER JOIN Person ON (Person.PersonID = PersonJob.PersonID) 
    GROUP BY 
     Job.CityID 
) NumDistinct ON (NumDistinct.CityID = Job.CityID) 
GROUP BY 
    Job.CityID 

이, 0.70sec에서 실행됩니다. 즉, LEFT JOIN'inig는 "원본 전체 쿼리"보다 5 배 빠르며 "해결 방법"보다 느린 속도는 20 %이며 읽기 및 확장이 훨씬 쉽습니다.