web-dev-qa-db-ja.com

SQL Serverの高コストの入れ子になったループ結合と遅延テーブルスプール

パラメータとして渡される値に関係なく、15〜16秒かかる以下のクエリを調整しようとしています。クエリは次のとおりです。

_select distinct d.documentpath as path, d.documentname as name, d.datecreated as created, pc.DateProcessed
from datagatheringruntime dgr 
 inner join processentitymapping pem on pem.entityid = dgr.entityid 
 inner join document d on d.entityid = pem.entityid or d.unitofworkid = pem.processid
 left join PendingCorrespondence pc on pc.PendingCorrespondenceId = d.PendingCorrespondenceId
 where rootid = @P0 and dgr.name in('cust_pn', 'case_pn')
OPTION(RECOMPILE)
_

クエリに関連するすべてのテーブル(〜_100GB_で非常に大きいDataGatheringRuntimeテーブルを除く)の統計を更新し、CTEを使用してクエリをリファクタリングしようとしましたが、同じ実行プランを取得していくつか必要です援助。

実際の実行計画はここにあります:

https://www.brentozar.com/pastetheplan/?id=ByUVIqlFE

問題は_nested loop join_の外部入力にあり、特にscanテーブルの非クラスター化_lazy table spool_インデックスのDocumentに続く_IX_Camunda_1_に問題があることは明らかですが、その問題に取り組む方法がわからないので、ガイダンスをいただければ幸いです。

enter image description here

3
Fza

ORdocumentの間の結合からprocessingentitymapping句を削除してみます

あなたはUNIONでそれを行うことができます

SELECT distinct d.documentpath as path, d.documentname as name, d.datecreated as created, pc.DateProcessed
FROM datagatheringruntime dgr 
INNER JOIN processentitymapping pem on pem.entityid = dgr.entityid 
INNER JOIN document d on d.entityid = pem.entityid 
LEFT JOIN PendingCorrespondence pc on pc.PendingCorrespondenceId = d.PendingCorrespondenceId
WHERE rootid = @P0 and dgr.name in('cust_pn', 'case_pn')
UNION
SELECT distinct d.documentpath as path, d.documentname as name, d.datecreated as created, pc.DateProcessed
FROM datagatheringruntime dgr 
INNER JOIN processentitymapping pem on pem.entityid = dgr.entityid 
INNER JOIN document d on d.unitofworkid = pem.processid
LEFT JOIN PendingCorrespondence pc on pc.PendingCorrespondenceId = d.PendingCorrespondenceId
WHERE rootid = @P0 and dgr.name in('cust_pn', 'case_pn')
OPTION(RECOMPILE);

その理由は、テーブルスプールがNESTED LOOPS演算子 enter image description here

そして、このネストされたループの演算子はOR述語です。 enter image description here

残りの9行になるまでフィルタリングします。

ORUNIONに変更すると、スプールが削除されます。ORを削除した後、インデックス作成を調べる必要がある場合があります。

UNIONで書き換えた後のパフォーマンスを向上させる可能性のあるインデックス

CREATE INDEX IX_EntityId
on document(EntityId)
INCLUDE(DocumentPath, DocumentName, DateCreated, PendingCorrespondenceId);

CREATE INDEX IX_UnitOfWorkId
on document(UnitOfWorkId)
INCLUDE(DocumentPath, DocumentName, DateCreated, PendingCorrespondenceId);

ここを参照 これに関する別の例

4
Randi Vertongen

処理する代わりにDataGatheringRuntime table which is quite big at ~100GB) mutiples回は、それらを#temp テーブル またはCTE

次に、Distinctを削除します。重複データがある場合は、重複データの背後にある理由を見つけ、正しいクエリを作成して重複データを削除します。

同じクエリでのDistinctUNIONの目的は何ですか?

Create table #temp(entityid int,processid int)
select pem.entityid,pem.processid
from datagatheringruntime dgr 
 inner join processentitymapping pem on pem.entityid = dgr.entityid 
 where rootid = @P0 and dgr.name in('cust_pn', 'case_pn')
 --OPTION(RECOMPILE)

 select d.documentpath as path, d.documentname as name, d.datecreated as created, pc.DateProcessed
from document d
left join PendingCorrespondence pc on pc.PendingCorrespondenceId = d.PendingCorrespondenceId
 where exists(select 1 from  #temp pem where  d.entityid = pem.entityid )

 UNION ALL

 select d.documentpath as path, d.documentname as name, d.datecreated as created, pc.DateProcessed
from document d
left join PendingCorrespondence pc on pc.PendingCorrespondenceId = d.PendingCorrespondenceId
 where exists(select 1 from  #temp pem where  d.unitofworkid = pem.processid )
0
KumarHarsh