問題は、ビジネス ロジックで必要とされるソートを「回避する方法」ではなく、外出先ではなく、インデックスを使用して予備的に行う方法です。
私はクエリプランを持っています:
|--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