哪些关键列用于包含WHERE子句的过滤索引?

哪些关键列用于包含WHERE子句的过滤索引?

问题描述:

我正在创建一个筛选索引,以便WHERE筛选器包含完整的查询条件。通过这样的索引,似乎不需要关键列,尽管SQL需要我添加一列。例如,考虑表:哪些关键列用于包含WHERE子句的过滤索引?

CREATE TABLE Invoice 
(
    Id INT NOT NULL IDENTITY PRIMARY KEY, 
    Data VARCHAR(MAX) NOT NULL, 
    IsProcessed BIT NOT NULL DEFAULT 0, 
    IsInvalidated BIT NOT NULL DEFAULT 0 
) 

查询在桌子上寻找新的发票的过程,即:

SELECT * 
FROM Invoice 
WHERE IsProcessed = 0 AND IsInvalidated = 0 

所以,我可以调整这些查询与筛选的索引:

CREATE INDEX IX_Invoice_IsProcessed_IsInvalidated 
ON Invoice (IsProcessed) 
WHERE (IsProcessed = 0 AND IsInvalidated = 0) 
GO 

我的问题:IX_Invoice_IsProcessed_IsInvalidated的关键列应该是什么?假定关键列未被使用。我的直觉导致我选择一个很小的专栏,并保持指数结构相对平缓。我应该选择表主键(Id)吗?其中一个过滤器列,或两者?

+1

您是否尝试查看针对没有索引的表的查询的执行计划,以查看建议的索引方式? – Tanner

+0

在测试了你的表并查看执行计划之后,没有建议任何索引,我怀疑这是因为你没有从位列索引中获得很多好处。这个问题似乎支持了起来http://*.com/questions/231125/should-i-index-a-bit-field-in-sql-server – Tanner

+0

@坦纳:我已经看过执行计划。查询优化器在索引中的行数小于表中行总数的情况下(预期方案)选择索引。我的问题是关于如何优化索引的效率(大小,I/O)。 –

因为你在该表上有一个聚集索引,所以放入该索引的关键字列中并不重要;意思Id是免费的。您唯一可以做的就是include索引的包含部分中的所有内容都可以在索引的叶级别实际拥有数据,以便将密钥查找排除在表之外。或者,如果队列很大,那么可能还有一些其他列在关键部分中很有用。

现在,如果该表没有主键,那么您必须将include或指定为键列才能用于连接或其他目的所需的所有列。否则,会在堆上进行RID查找,因为在索引的叶级上,您将引用数据页。

这个过滤后的指标覆盖了多少百分比?如果它很小,则可能需要覆盖整个表以处理索引中的“SELECT *”而不触碰表。如果它是桌子的一大部分,尽管这不会是最佳的。然后我建议使用聚集索引或主键。我必须研究更多,因为我现在忘记了哪一个是最优的,但如果它们是相同的,那么应该设置。

+0

索引中的行数与表中的总行数相比较小,这就是我选择过滤索引的原因。你能否详细说明为什么要使用聚集索引/主键? “最佳”是什么意思? –

我建议你把它声明如下

CREATE INDEX IX_Invoice_IsProcessed_IsInvalidated 
ON Invoice (Id) 
INCLUDE (Data) 
WHERE (IsProcessed = 0 AND IsInvalidated = 0) 

的include子句将意味着数据列的值将被存储为索引的一部分。

如果你没有一个include子句然后

SELECT Id, Data 
FROM Invoice 
WHERE IsProcessed = 0 AND IsInvalidated = 0 

查询计划将包括两个步骤

  • 使用索引来查找匹配的主键值的列表 标准
  • 从表中获取与这些主键匹配的数据

另一方面,如果索引包含[数据]列,那么它将正确覆盖查询,因为不需要使用主键查找数据。

您没有得到什么都没有

这样做的缺点是,你将为这些记录存储varchar(MAX)数据两次,因此需要将更多的数据写入数据库,并且会使用更多的存储,尽管这不是这样如果你只是在讨论一小部分数据,那么问题就很大。

一如往常,您将更多的时间和精力放在仔细考虑之中,让他们更快更容易。