web-dev-qa-db-ja.com

同じクエリ、同じワークステーション、異なる実行プラン

まったく異なる実行プランを生成する2つの異なるデータベースに対して、同じワークステーションで同じクエリを実行しました。構造とインデックスは同じです。唯一の違いはデータです。奇妙なことに、「database1」のデータは「database2」のデータよりもはるかに少なく、パフォーマンスが低下します(database2はdatabase1の半分の時間を要します)。 ItemPropertiesテーブルに明らかな設計上の欠陥があることに気付くでしょう。この設計が不十分なテーブルの構造を変更する予定ですが、その前に、最適化のアイデアを探しています。これは両方のデータベースの情報です。

データベース1:[実際の実行計画] https://www.brentozar.com/pastetheplan/?id=HyVv5-PE-

データベース2:[実際の実行計画] https://www.brentozar.com/pastetheplan/?id=rJrzjbDVW

3
Patrick

気づいた違い:

  • スロープランはバージョン120カーディナリティエスティメータを使用します
  • 高速プランはバージョン70カーディナリティエスティメータを使用します

クエリトレースフラグ9481を使用してバージョン70の使用を強制することができます-OPTION(QUERYTRACEON 9481)を追加するだけです。

次に、ItemPropertiesテーブルは両方のケースで異なる方法で処理されます。高速プランでは、各結合に最大1つのプロパティが存在すると想定されていますが、低速プランでは、2つが存在すると想定されています。問題のすべてのケースで実際にプロパティ値が1つしかないと仮定すると、左結合を内部クエリに置き換えることができます。これにより、両方のサーバーで同じ計画が作成されます。

[〜#〜] edit [〜#〜]別の最適化の機会には、 PIVOT演算子 を使用してすべてのプロパティを一度にフェッチすることが含まれます。そのようです:

SELECT
vw_Items.ID
,vw_Items.ResolvedEntityID
,vw_Items.ResolvedDescription
,vw_Items.ItemProductNumber
,vw_Items.ItemDescription
,vw_Items.FilteringType
,vw_Items.ItemCategory
,vw_Items.IsDefault
,vw_Items.IsInventoryType
,vw_Items.Active
,vw_Items.PlantFloorVisible
,[dbo].f_ParseDistanceValue([Length]) AS 'Length'
,[dbo].f_ParseDistanceValue(Width) AS Width
,ISNULL(MaterialDescription.[Description], '(none)') AS 'Material'
,ISNULL(GradeDescription.[Description], '(none)') AS 'Grade'
,ISNULL(MillingDescription.[Description], '(none)') AS 'Milling'
,ISNULL(StateDescription.[Description], '(none)') AS 'State'
FROM
vw_Items
-- Join to get properties
left join (
    select [ItemEntityID],[Property],[Value] from [dbo].[ItemProperties]) p
    PIVOT (MAX(VALUE) for [Property] in (Material,Grade,Milling,State,Length,Width))properties on vw_Items.[EntityID] = properties.[ItemEntityID]
LEFT JOIN DescriptionEntity  AS MaterialDescription ON properties.Material = MaterialDescription.EntityID
LEFT JOIN DescriptionEntity  AS GradeDescription ON properties.Grade = GradeDescription.EntityID
LEFT JOIN DescriptionEntity  AS MillingDescription ON properties.Milling = MillingDescription.EntityID
LEFT JOIN #DescriptionEntity  AS StateDescription ON properties.[State] = StateDescription.EntityID

PIVOTを使用すると、サーバーはItemPropertiesテーブルに1回だけアクセスするため、IOが低下する可能性があります。

2
Daniel Jelinski