web-dev-qa-db-ja.com

なぜ内部結合は非表示のソートを導入するのですか?

次の例を考えてみます。

DECLARE @suppliedNumber MONEY
SET @suppliedNumber = 245656.00

SELECT 
    ah.FirstName, 
    ah.LastName
FROM 
    AccountHolders AS ah
JOIN 
    [dbo].[Accounts] AS a
ON 
    ah.Id = a.AccountHolderId
GROUP BY 
    ah.FirstName, ah.LastName
HAVING SUM(a.Balance) > @suppliedNumber

ご覧のとおり、クエリにはどのような順序もありません。しかし、実行プランを見ると、暗黙的なソートが見られます。

SSMS Execution plan

なぜこうなった?これの背後にある技術的な理由は何ですか?

Microsoft SQL Server 2014(RTM-CU14)(KB3158271)-12.0.2569.0(X64)2016年5月27日15:06:08 Copyright(c)Microsoft Corporation Express Edition(64-bit)on Windows NT 6.3(Build 14393:)

4
iPath ツ

@sp_BlitzErikがコメントで述べたように、 ストリーム集計演算子 では、入力をソートする必要があります。

ストリーム集約演算子は、1つ以上の列で行をグループ化し、クエリから返された1つ以上の集約式を計算します。この演算子の出力は、クエリの後の演算子によって参照されるか、クライアントに返されるか、またはその両方です。 Stream Aggregateオペレーターは、グループ内の列で順序付けられた入力を必要とします。前のソート演算子または順序付けされたインデックスシークまたはスキャンのためにデータがまだソートされていない場合、オプティマイザはこの演算子の前にソート演算子を使用します。 SHOWPLAN_ALLステートメントまたはSQL Server Management Studioのグ​​ラフィカル実行プランでは、GROUP BY述語の列がArgument列にリストされ、集計式がDefined Values列にリストされます。

FirstName, LastNameにインデックスを追加すると、並べ替えがなくなる場合があります(クエリオプティマイザーがインデックスを使用する場合)。

7
Max Vernon

joinがソートを生成しているとは思いません

group bysumがソートを生成しています
クエリプランでの順序を確認する

これはもっと速いかもしれません
目的が同じ名前の複数のアカウントである場合は機能しません

SELECT ah.Id, ah.FirstName, ah.LastName
FROM 
    AccountHolders AS ah
JOIN 
    [dbo].[Accounts] AS a
ON 
    ah.Id = a.AccountHolderId
GROUP BY 
    ah.Id, ah.FirstName, ah.LastName
HAVING SUM(a.Balance) > @suppliedNumber 

または

SELECT ah.Id, ah.FirstName, ah.LastName
FROM AccountHolders AS ah
JOIN ( select AccountHolderId
       from [dbo].[Accounts] A
       GROUP BY Id 
       HAVING SUM(Balance) > @suppliedNumber 
     ) a
 on a.AccountHolderId = ah.ID  
7
paparazzo