1

問題は、ビジネス ロジックで必要とされるソートを「回避する方法」ではなく、外出先ではなく、インデックスを使用して予備的に行う方法です。

私はクエリプランを持っています:

|--Sort(TOP 5, ORDER BY:([this_].[DateAdded] DESC))
   |--Nested Loops(Inner Join, OUTER REFERENCES:([this_].[Id], [Expr1002]) OPTIMIZED WITH UNORDERED PREFETCH)
        |--Index Seek(OBJECT:([storm].[dbo].[Items].[IX_Items_ByLocationSorted] AS [this_]), SEEK:([this_].[Status]=(1) AND [this_].[RegionId]=(32) AND [this_].[LocationId]=(32001)),  WHERE:([storm].[dbo].[Items].[SubcategoryTypeId] as [this_].[SubcategoryTypeId]=(88) AND ([storm].[dbo].[Items].[IsHidden] as [this_].[IsHidden]<(1) OR [storm].[dbo].[Items].[IsHidden] as [this_].[IsHidden]>(1))) ORDERED FORWARD)
        |--Clustered Index Seek(OBJECT:([storm].[dbo].[Items].[PK_Items] AS [this_]), SEEK:([this_].[Id]=[storm].[dbo].[Items].[Id] as [this_].[Id]) LOOKUP ORDERED FORWARD) 

ご覧のとおり、Index Seek 操作は一連の行を返します。Query Optimizer は Key Lookup を実行して行全体を取得し (とにかく返す必要があるため)、DateAdded 列ですべての行を並べ替えます。これは明白で完全に有効な動作です。しかし、Index Seek によって返される行数 (最大 30k) を考慮すると、非常に低速です (最大 40 秒かかる場合があります)。

このクエリを高速化し、この移動中の並べ替えを回避するにはどうすればよいですか?

PS: クエリ対象のテーブルには約 300 万行あり、頻繁に更新されます。これによりページがロックされる可能性がありますが、それらのロックが 40 秒続くとは思えません。

クエリ:

SELECT TOP 5 * 
FROM Items 
WHERE 
     SubcategoryTypeId = 88 
     and RegionId = 32
 and LocationId = 32001
 and not (IsHidden = 1 and Status = 1) 
 ORDER BY DateAdded desc
4

3 に答える 3

6

キー ルックアップを削除するには、カバリング インデックスが必要です

これにより、2 セットのデータを照合するために必要な中間ソート ( ORDERED FORWARD) が削除されます (PK ルックアップと交差するインデックス シーク)

編集:

コメントの後: 大きなインデックスを維持する (大きく定義しますか?) か、パフォーマンスを低下させてライブを行います。インデックスが貧弱な場合、高速なパフォーマンスは得られません。二者択一です。

于 2011-03-28T16:47:45.720 に答える
3

あなたの説明とSQL Serverがインデックスを処理する方法に基づいて、いいえ。

並べ替えは必要な手順であり、SQL Server データには "固有の" 順序はありません。インデックス化されたデータ、インデックスの作成スクリプトに基づいて並べ替えられますが、それでも解決策があるようです。

gbn が正しく指摘しているように、カバリング インデックスはあなたのパフォーマンスにいくらか役立ちますが、あなたはそれを行うことに興味がないことをコメントで確立しました。要件またはデータ構造の変更。

于 2011-03-28T17:47:21.417 に答える
1

部分的なカバリング インデックスを作成したい場合は、次のようなことができるはずです (このコードは私のテーブルに基づいていることに注意してください。必要に応じて変更する必要があります)。

    select
    b.*
from
(
    select 
        IDkey,
        row_number() over (order by Years, Months) as z
    from dbo.tblWIN_LOSS
    where Won>=10000
) a
    inner join dbo.tblWIN_LOSS b
        on a.IDkey=b.IDkey
where a.z<=5

これでパフォーマンスが向上するかどうかは 100% わかりませんが、そうすべきだと思います。

編集:ああ、あなたはnhibernateがクエリを返すと言ったので、何ができるかわかりません。

于 2011-03-28T19:49:42.360 に答える