web-dev-qa-db-ja.com

長いGROUP BYリストをサブクエリに置き換える

これはスタックオーバーフローに関する私の質問の再投稿です。彼らはここでそれを尋ねることを提案しました:

私は オンライン記事 を2005年に発見しました。著者は、多くの開発者がGROUP BYを間違って使用しており、サブクエリに置き換えるほうがよいと主張しています。

私はクエリの1つでテストしました。別のテーブルの結合されたエントリの数で検索結果を並べ替える必要があります(より一般的なものが最初に表示されます)。私の元の古典的なアプローチは、両方のテーブルを共通IDで結合し、選択リストの各フィールドでグループ化し、サブテーブルの数で結果を並べることでした。

ここで、リンクされたブログのJeff Smithは、すべてのグループ化を行う副選択を使用し、その副選択に参加するよりも適切であると主張しています。両方のアプローチの実行計画を確認すると、SSMSでは、大規模なグループでは52%の時間と48%の副選択が必要になるため、技術的な観点からは、副選択のアプローチは実際にはわずかに高速であるように見えます。ただし、「改善された」SQLコマンドは、より複雑な実行計画を生成するようです(ノードに関して)。

どう思いますか?この特定のケースで実行プランを解釈する方法と、一般的にどちらが望ましいオプションかについて、詳細を教えてもらえますか?

SELECT
    a.ID,
    a.ID_AddressType,
    a.Name1,
    a.Name2,
    a.Street,
    a.Number,
    a.ZipCode,
    a.City,
    a.Country
FROM dbo.[Address] a
INNER JOIN CONTAINSTABLE(
    dbo.[Address],
    FullAddress,
    '"ZIE*"',
    5
) s ON a.ID = s.[KEY]
LEFT JOIN dbo.Haul h ON h.ID_DestinationAddress = a.ID
GROUP BY
    a.ID,
    a.ID_AddressType,
    a.Name1,
    a.Name2,
    a.Street,
    a.Number,
    a.ZipCode,
    a.City,
    a.Country,
    s.RANK
ORDER BY s.RANK DESC, COUNT(*) DESC;

SELECT
    a.ID,
    a.ID_AddressType,
    a.Name1,
    a.Name2,
    a.Street,
    a.Number,
    a.ZipCode,
    a.City,
    a.Country
FROM dbo.[Address] a
INNER JOIN CONTAINSTABLE(
    dbo.[Address],
    FullAddress,
    '"ZIE*"',
    5
) s ON a.ID = s.[KEY]
LEFT JOIN (
    SELECT ID_DestinationAddress, COUNT(*) Cnt
    FROM dbo.Haul
    GROUP BY ID_DestinationAddress
) h ON h.ID_DestinationAddress = a.ID
ORDER BY s.RANK DESC, h.Cnt DESC;

enter image description here

8
André Reichelt

dbo.Haulを使用して左結合をサブクエリに変更すると、スキャンからデータを取得した直後に、ID_DestinationAddress(ストリーム集計)のこれらの個別の値が計算され、それらがカウントされます(計算スカラー)。

これは、実行計画に表示されているものです。

enter image description here

一方、GROUP BYメソッドを使用する場合、データはdbo.Hauldbo.[Address]の間の左結合を通過した後にのみグループ化を行います。

enter image description here

それがどれほど良いかは、dbo.Haulの一意の値の比率に依存します。一意の値が少ないほど、左結合で処理する値が少なくなるため、2番目の実行プランの結果が向上します。

2番目のクエリの他の肯定的な結果は、ID_DestinationAddressの一意性のみが計算され、グループ化された列全体の一意性は計算されないことです。

ここでも、クエリ、データセット、インデックスの結果をテストして検証する必要があります。実行プランに慣れていない場合にテストする方法の1つは、クエリを実行する前にSET STATISTICS IO, TIME ON;を設定し、これらのランタイム統計を statisticsparser などのツールに貼り付けることで読みやすくします。


テスト中

データの違いがこれらのクエリで何ができるかを示すための小さなテスト。

dbo.Haulテーブルに、FULLTEXTインデックスフィルタリングによって返された5つのレコードとの一致が多くない場合、違いはそれほど大きくありません。

クエリプランごとにグループ化

サブクエリクエリプラン

1000行は以前にフィルタリングされる可能性がありますが、私のマシンではどちらのクエリでも実行時間は約15msです。

次に、これらの5つのレコードが左側の結合のdbo.Haulとさらに多く一致するようにデータを変更した場合:

group by queryの違いenter image description here

    <QueryTimeStats CpuTime="1564" ElapsedTime="1566" />

そして Subquery はより明確になります

enter image description here

そして統計:

<QueryTimeStats CpuTime="680" ElapsedTime="690"/>
8
Randi Vertongen