2016-10-19 34 views
4

クエリ説明:COUNT(1)+ COUNT(DISTINCT())2つのクエリを実行次に、はるかに遅いが別々

  • PersonPersonIDにより同定)が持っているか、(JobIDによって識別される)対応Jobを有していなくてもよいです。
  • 対応するJobがある場合、結合は表PersonJobPersonID < =>JobID)に格納されます。
  • PersonJobを指定しない場合は無視されます。
  • Jobもまた、CityIDを有する。すべてのJob.CityIDパー
  • 、クエリがPersonの合計数を知っているとも

Person.HouseIDユニークなクエリのカウントしたい:

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
  • SELECT COUNT(1) FROM Person〜800.000
  • SELECT COUNT(DISTINCT(Person.HouseID)) FROM Person〜10.000
  • SELECT COUNT(1) FROM Job〜500
  • MS SQL Serverの10.50

問題:

  • COUNT(1)クエリの一部、個別に実行、0.25secで実行されます。

    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で実行されますか?

実行計画:

  • 私は申し訳ありませんが、それらを読み取るには専門家です。
  • 私の知る限り、問題はCOUNT(DISTINCT)内にある
  • 部分クエリで:
    • 25%のハッシュが一致(集約)(出力Job.CityID
    • 15%のハッシュが一致(インナー参加)(出力Job.CityIDPerson.HouseID
      • 30%のインデックス・スキャン(出力Person.PersonIDPerson.HouseID
      • 14%インデックス(求めて出力PersonJob.PersonID
    • 完全クエリで
    • 03パーセントのハッシュ一致(部分集合体)(出力Job.CityIDCOUNT(*)
    • 31%のハッシュ一致(集計)(出力Job.CityID
    • 29%テーブルスプール(出力Job.CityID,Person.HouseID
+0

あなたの比較は 'join'sを使用していますか? –

+0

あなたが何を意味するのかわからない、おそらく部分的なクエリですか?それらを追加しました。 – Codeguard

+0

無関係ですが、: 'distinct'は***ではありません*** ***関数です。 '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

マーティン・スミスの回避策を読んだ後では、回避策が理解しにくく、理解が難しく、追加のDISTINCT列が必要になると完全に混乱することになりました。私は次のように部分的なクエリをJOINを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%だけ遅く、読み取りと拡張がはるかに容易であることを意味します。

関連する問題