为什么我不能索引并在索引中包含相同的列?

时间:2012-12-10 19:21:44

标签: sql-server sql-server-2008 indexing

为什么我不能做以下的事情?我希望这个“常用”列上的过滤器既快又能够在不需要表扫描的情况下返回它。

CREATE NONCLUSTERED INDEX Ix_Foo
ON Foo (ForeignKeyID, ObjectID)
INCLUDE (ObjectID)

当我这样做时,我收到错误:

  

不能在索引中使用重复的列名。列名'ObjectID'不止一次列出。

我喜欢这样的查询,我想要返回ObjectID以及过滤它。这里的子查询是我的意思的一个例子:

SELECT something FROM Bar
WHERE Bar.FooID IN
  (SELECT ObjectID FROM Foo WHERE ForeignKeyID=13 AND ObjectID IN (12, 13, 14, 15))

我在概念上缺少什么?

2 个答案:

答案 0 :(得分:6)

原因是ObjectId已作为关键列包含在索引中,并且您尝试将其作为非关键列包含在内,这是不必要的。

CREATE NONCLUSTERED INDEX Ix_Foo
ON Foo (ForeignKeyID, ObjectID)

这应该足以满足您的目的。

您通常需要包含非键列,以便(引用MSDN):

  • 它们可以是不允许作为索引键列的数据类型。

  • 在计算索引键列数或索引键大小时,数据库引擎不会考虑它们。

答案 1 :(得分:2)

从概念上讲,SQL Server中未过滤的非聚集索引中的叶级别在基础表中每行有1行数据。叶级别中的列是以下不同的列:

  • 构成索引键的列。 (所以我们可以浏览索引)
  • 指向基表中相应行的概念性指针。 (所以我们可以回到基表中的相应行)
    • 对于堆,指针是RID或行标识符
    • 对于聚簇索引,指针是构成聚簇索引的关键列
  • 任何包含的列(额外的列被卡住了)

例如:

CREATE TABLE t1 (id int not null, first_name varchar(20), last_name varchar(20))
CREATE CLUSTERED INDEX CIX_t1 on t1 (id)
CREATE INDEX IX_t1_a on t1 (first_name)
CREATE INDEX IX_t1_b on t1 (first_name) INCLUDE (id)
CREATE INDEX IX_t1_c on t1 (first_name) INCLUDE (id, last_name)
CREATE INDEX IX_t1_d on t1 (first_name, last_name)
CREATE INDEX IX_t1_e on t1 (first_name, id)

IX_t1_a的叶级由(first_name,id)

组成

IX_t1_b的叶级由(first_name,id)

组成

IX_t1_c的叶级别由(first_name,id,last_name)

组成

IX_t1_d的叶级别由(first_name,id,last_name)

组成

IX_t1_e的叶级由(first_name,id)

组成

列永远不会包含两次。在上面的示例中,索引a,b,c是彼此重复的。同样,索引c和d也是重复的。 (根据聚簇索引和非聚簇索引的唯一性,非叶级别存在细微差别,但索引可用于哪些查询,它们是相同的。)