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 操作返回一组行。比查询优化器执行键查找来检索整行(因为无论如何他都必须返回它),然后它按 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 回答