ORDER BY索引列仍然很慢

时间:2015-01-27 18:36:43

标签: sql asp.net sql-server performance sql-server-2008

我有以下查询,<使用ORDER BY b.Price时为1,使用ORDER BY b.Price DESC时为10秒

select * from
(
    select  
        /* When changed to ORDER BY b.Price DESC it's 10x slower! */
        (row_number() over (ORDER BY b.Price)) as RowNumber,
        b.*     
    from
        Books b (nolock) 
        inner join BookPublishRegions p (nolock)
          on b.BookKey = bp.BookKey
    where       
        contains(p.PublishRegionName, 'France')
) as t1
where t1.RowNumber between 100 and 110

对于为什么有任何想法?

我在b.Price上有一个升序和降序索引。我不确定我还能在这做什么......

作为参考,我包括以下两个索引的CREATE脚本:

CREATE NONCLUSTERED INDEX [IX_Books_PriceDesc] ON [dbo].[Books] 
(
    [Price] DESC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]


CREATE NONCLUSTERED INDEX [IX_Books_Price] ON [dbo].[Books] 
(
    [Price] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

5 个答案:

答案 0 :(得分:2)

正如另一位用户所提到的,如果没有查看查询计划,那就是疯狂的猜测。但如果查询在任何一种情况下都使用索引,我会感到惊讶。即使它们覆盖索引,你在子查询中过滤窗口函数的结果,规划器也无法知道row_number函数将返回100-110哪些行,直到它解析了整个结果集。子查询,您实际上还没有按价格对子查询进行排序,因此使用任一索引都没有任何好处。我无法解释为什么在这些条件下上升的情况会更快,但是我们必须看到一个查询计划来解决这个问题,但我怀疑还有其他的东西可能会起作用。

看起来你正在使用窗口函数来实现分页,如果是这样,并且你使用的是2012或更高版本,请尝试使用offset / fetch,例如:

select  
    b.*     
from
    Books b (nolock) 
    inner join BookPublishRegions p (nolock)
      on b.BookKey = bp.BookKey
where       
    contains(p.PublishRegionName, 'France')
order by price desc 
offset 100 fetch 10

计划者可能会意识到它可以使用索引。虽然它可能需要成为聚集或覆盖索引才能说实话。

如果你是在2008年或更早的时候,请尝试在子查询中按顺序排列显示顺序,以便规划人员意识到它可以使用索引。您仍然可以使用窗口函数并在外部查询中进行过滤来进行分页,但这样可以在很少的行上运行窗口函数:

select * from
(
select top 110
    (row_number() over (ORDER BY b.Price DESC)) as RowNumber,
    b.*     
from
    Books b (nolock) 
    inner join BookPublishRegions p (nolock)
      on b.BookKey = bp.BookKey
where       
    contains(p.PublishRegionName, 'France')
ORDER BY b.Price DESC
) as t1
where t1.RowNumber between 100 and 110

答案 1 :(得分:0)

我会查看SSMS中的估计查询计划(Ctrl + L)。我怀疑它没有使用任何一个索引,因为它们没有覆盖。

此外,在较慢的降序选项的情况下,它引入了另一个排序选项,因为数据可能已经排序到选定的连接策略。

不看实际的查询计划,这只是疯狂的猜测

答案 2 :(得分:0)

您是否尝试过按降序使用升序索引?根据这篇文章,它应该以这样的方式快速地执行,以便具有升序索引和升序,并且消除了对降序索引的需要。自快速实验以来值得一试。 Building SQL Server Indexes in Ascending vs Descending Order

答案 3 :(得分:0)

我会尝试将索引编码到Select语句中。由于您已预定义索引。

语法是

With (NOLOCK, Index(Index_Name))

答案 4 :(得分:0)

两种情况都使用您提到的索引吗?或者是使用另一个索引的ASC示例,该索引不需要对“。*”选择进行键查找。