嗯,问题并不是“如何避免”排序,因为它是业务逻辑所要求的,而是如何使用索引进行初步预测,而不是在旅途中。
我有一个查询计划:
|--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操作返回一组行。比查询优化器执行密钥查找以检索整行(因为他无论如何都必须返回它),而不是按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
答案 0 :(得分:6)
您需要covering index才能删除key lookup
这将删除匹配2组数据所需的中间排序(ORDERED FORWARD
)(索引搜索与PK查找相交)
编辑:
评论之后:维持一个大的索引(定义大?)或生活缓慢的表现。索引不佳,无法获得快速性能。这是一个二元选择。
答案 1 :(得分:3)
根据您的描述以及SQL Server如何处理索引,编号
排序是必要的步骤,SQL Server数据没有“固有”顺序。索引数据 基于索引的创建脚本进行排序,但看起来您无论如何都会有一个度假胜地。
正如gbn正确指出的那样,覆盖指数可以帮助你的表现,但是你在评论中确定你对此没有兴趣,所以你可能处于一个你无法获得的表现平台不改变要求或数据结构。
答案 2 :(得分: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
我不是百分百确定这是否会给你带来性能提升,但我认为应该这样做。
编辑:啊,你说nhibernate正在返回查询,所以我不知道你能做什么。