これは、レポートに対して実行しているクエリです。 offset
とfetch
なしで実行するには、約20秒かかります。この2つでは、クエリは10分で完了しません。
select *
-- h.ActionDate as Date, h.Action, h.Actor , h.PaymentLotNo
-- , sh.OwnerName as OwnersName,sh.TECHID as TechId, sh.Id as SubsidyCardId, sh.TotalSubsidy as SubsidyAmount
-- ,a.ToleEng + '-' + v.NameEng + cast(a.Ward as nvarchar(4)) + ',' + d.NameEng + ',' + s.StateNameEng as Address
from common.CTB_SUBSIDY_APPLICATION_HISTORY h
join fsams.CTB_SUBSIDY_CARD_HEADER sh on sh.LotNumber = h.PaymentLotNo
join fsams.CTB_SUBSIDY_CARD_ADDRESS sa on sa.SubsidyId = sh.Id
join common.CTB_ADDRESS a on a.AddressID = sa.AddressId
join COMMON.CLK_STATE s on s.StateId = a.StateID
join COMMON.CLK_DISTRICTS d on d.DistrictCd = a.DistrictCD
join common.CLK_DISTRICT_VDC v on v.VdcCd = a.VdcCd where 1 = 1 order by h.ActionDate desc
offset 790 rows
FETCH first 10 row only
以下は、クエリの 実行プラン です。
このクエリを最適化するにはどうすればよいですか?
_OFFSET...FETCH
_を使用すると、行の目標が導入される可能性があります(TOP
がそうするのと同じように、 実行計画での行の目標の設定と識別 を参照)その主題の詳細については、Paul Whiteを参照してください)。これが、クエリのその部分なしでこのような違いが見られる理由です。行の目標がないと、計画が完全に変わります。
行の目標により、SQL Serverは、共有した実行プランで一連のネストされたループ結合を選択します。これは通常は問題ありませんが、結合は推定値よりも制限が厳しいため、要求された10行を取得するのに予想よりもかなり時間がかかると思います。
クエリの最後にOPTION (QUERYTRACEON 4138)
を追加して再度実行することで、この理論をテストできます。
適切なソリューションに関する限り-Dan Guzmanが示唆したように、_fsams.CTB_SUBSIDY_CARD_HEADER
_に狭いインデックスを作成してみることができます。
_CREATE NONCLUSTERED INDEX IX_PaymentLotNo
ON FSAMS.CTB_SUBSIDY_CARD_HEADER (PaymentLotNo)
INCLUDE (OwnerName, TECHID, Id, TotalSubsidy)
_
また、実際のクエリの列リストと比較して、最終的に得られる最終的な計画が確実に変更されるため、パフォーマンス関連のテストに_SELECT *
_を使用しないでください。
クエリの推定値をスローする可能性がある暗黙的な変換が行われています-LotNumber
は_CTB_SUBSIDY_CARD_HEADER
_テーブルに文字列として保存され、int
に変換されてから_CTB_SUBSIDY_APPLICATION_HISTORY
_のPaymentLotNo
に参加しました。可能であれば、これらの列をALTER
一致するデータ型にする必要があります。
補足:サポートされていないSQL Server 2014 RTMを実行しています。最新のサービスパックにアップグレードする必要があります。また、発生している問題couldはその後修正されたオプティマイザのバグに関連しているため、その時点でTF 4199を有効にすることを検討してください。
Dan Guzmanが言ったように、fsams.CTB_SUBSIDY_CARD_HEADER(LotNumber)にインデックスを追加する必要があります。このテーブルのクラスター化インデックススキャンは、クエリのコストの59%を表します。
また、sh.LogNumberとh.PaymentLotNoは同じタイプではないようです。 sh.LotNumberの計画で暗黙の変換警告が表示されます。修正する必要があります。
そして、あなたはSELECT *なしで新しい計画を貼り付ける必要があります
クエリを実行すると、見積もりプランだけでなく実際の実行プランも取得できます。このようにして、推定行数と実際の行数が一致するかどうか、統計が古くなっていないかどうかを確認することもできます。
まず、クエリのwhere 1=1
も明確ではありません。
すべての提案とは別に、指定されたクエリを改善する主要なスコープが1つあります。
メインクエリのみにPaging
を適用します。ページングの行数に影響を与えるメインクエリ。
メインクエリがよくわからない場合は、例を挙げて説明します。
;With CTE as
(
select
h.ActionDate as Date, h.Action, h.Actor , h.PaymentLotNo
, sh.OwnerName as OwnersName
,sh.TECHID as TechId
, sh.Id as SubsidyCardId
, sh.TotalSubsidy as SubsidyAmount
,a.ToleEng + '-' + v.NameEng + cast(a.Ward as nvarchar(4)) + ',' + d.NameEng + ',' + s.StateNameEng as Address
from fsams.CTB_SUBSIDY_CARD_HEADER sh
join common.CTB_SUBSIDY_APPLICATION_HISTORY h on sh.LotNumber = h.PaymentLotNo
join fsams.CTB_SUBSIDY_CARD_ADDRESS sa on sa.SubsidyId = sh.Id
where 1 = 1 order by h.ActionDate desc
offset 790 rows
FETCH first 10 row only
)
select
sa.*
from CTE sa
join common.CTB_ADDRESS a on a.AddressID = sa.AddressId
join COMMON.CLK_STATE s on s.StateId = a.StateID
join COMMON.CLK_DISTRICTS d on d.DistrictCd = a.DistrictCD
join common.CLK_DISTRICT_VDC v on v.VdcCd = a.VdcCd
最終結果セットのMaster
テーブルを常に結合します。
それが明らかで、可能であれば、CTE
内の結合からいくつかのテーブルを削除して、最終的なクエリに含めることができます。
CTEの結果をTemp
テーブルに入れます。