如何为非聚集索引定义列顺序

时间:2012-05-18 15:36:07

标签: sql-server-2008 non-clustered-index

我写了一个像这样的子查询:

select top 1 A
from my_table
where B = some_joined_value_from_outer_query
order by C desc

我想创建一个非聚集索引,以提高此部分的性能。

这里有3个问题:

  1. 索引列的正确顺序是什么?
  2. 此外,列A应该是索引列还是仅包含在索引中?
  3. 这可以在没有子查询的情况下重写(注意top 1order by desc)并且可以改善性能吗?

  4. 修改 这是查询(数据同步过程的一部分):

    SELECT ProductId, (
        SELECT Id 
        FROM [Order]
        WHERE Number = (
            SELECT TOP 1 OrderNumber
            FROM OtherDatabase..ReferenceTable
            WHERE ProductNumber = Product.Number
            ORDER BY [Date] DESC)
        ) AS OrderId
    FROM Product
    

3 个答案:

答案 0 :(得分:4)

(A)

CREATE NONCLUSTERED INDEX foo ON dbo.my_table(B, C DESC) INCLUDE (A);

(B)

由于A不在WHEREORDER BY,因此它可能只在INCLUDE d列的列表中,因为它只是“沿途”并且不是必需的成为关键的一部分。

(C)

没有更多背景,无法回答。为什么你只要包含子查询然后询问我们看不到的外部查询?

编辑关于与@Quassnoi的持续对话,我只想快速演示非聚集索引中的尾随列的排序方向特定查询使用的计划有很大差异。让我们采取以下设计的例子:

CREATE TABLE dbo.foo1(A INT, B INT, C INT);
CREATE NONCLUSTERED INDEX foo1x ON dbo.foo1(B, C) INCLUDE(A);

CREATE TABLE dbo.foo2(A INT, B INT, C INT);
CREATE NONCLUSTERED INDEX foo2x ON dbo.foo2(B, C DESC) INCLUDE(A);

INSERT dbo.foo1 SELECT TOP (500000) c.[object_id], c.[object_id], -1*c.[object_id]
FROM sys.all_columns AS c CROSS JOIN sys.all_objects
ORDER BY c.[object_id];

INSERT dbo.foo2 SELECT TOP (500000) c.[object_id], c.[object_id], -1*c.[object_id]
FROM sys.all_columns AS c CROSS JOIN sys.all_objects
ORDER BY c.[object_id];

现在,让我们运行这两个提议的查询并检查计划:

SELECT  A
FROM    (
        SELECT  A, ROW_NUMBER() OVER (PARTITION BY B ORDER BY C DESC) RN
        FROM    dbo.foo1
        ) q
WHERE   rn = 1;

SELECT  A
FROM    (
        SELECT  A, ROW_NUMBER() OVER (PARTITION BY B ORDER BY C DESC) RN
        FROM    dbo.foo2
        ) q
WHERE   rn = 1;

这是针对dbo.foo1(其中C是ASC)的查询计划:

enter image description here

enter image description here

我提到的那种:

enter image description here


这是针对dbo.foo2(其中C是DESC)的查询计划:

enter image description here

enter image description here


现在,如果向内部查询添加WHERE子句(例如WHERE B = -1024577103),则计划更相似。但是那也意味着PARTITION BY是不必要的,并且需要进行一些匹配以将外部查询限制为B的值。但是我的观点仍然是,对于问题中的特定查询,索引中每列的排序方向可能对计划几乎没有影响,但对于所有可以使用相同索引的查询都不是这样。

答案 1 :(得分:0)

订单确实很重要。第一顺序的列是最重要的。

索引的选择完全基于第一列。仅当在查询中使用索引中列出的第一列时,才考虑使用索引。因此,如果第一列没有匹配,并且在查询的JOIN,ORDER BY或WHERE子句中使用了列,则完全忽略index。

答案 2 :(得分:0)

你可以像这样重写它:

SELECT  m.a
FROM    (
        SELECT  m.a, ROW_NUMBER() OVER (PARTITION BY m.b ORDER BY m.c DESC) RN
        FROM    outer_table o
        JOIN    my_table m
        ON      m.b = o.b
        ) q
WHERE   rn = 1

但子查询实际上可能更快(或可能不会)。

请参阅我的博客中的此条目: