我正在创建一个过滤索引,以便WHERE过滤器包含完整的查询条件。对于这样的索引,似乎不需要键列,尽管SQL要求我添加一个。例如,请考虑表:
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
)吗?其中一个过滤列,或两者都是?
答案 0 :(得分:1)
因为你在该表上有一个聚集索引,所以你放在该索引的键列中的内容并不重要;意思Id
是免费的。您可以做的唯一事情是include
索引的包含部分中的所有内容,实际上在索引的叶级别实际拥有数据,以排除对表的键查找。或者,如果队列很大,那么,或许,其他一些列在关键部分会很有用。
现在,如果该表没有主键,那么您必须include
或指定加入或其他目的所需的所有列作为键列。否则,将发生堆上的RID查找,因为在索引的叶级别上,您将引用数据页。
答案 1 :(得分:0)
此过滤索引覆盖的表的百分比是多少?如果它很小,你可能想覆盖整个表来处理" SELECT *"从索引没有击中表。如果它是表格的一大部分,虽然这不是最佳的。然后我建议使用聚簇索引或主键。我不得不进行更多的研究,因为我忘了现在哪个是最优的,但如果它们相同则应该设置。
答案 2 :(得分: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
将涉及两个步骤
另一方面,如果索引包含[Data]列,那么它将正确覆盖查询,因为不需要使用主键查找数据
尽管
,你什么也得不到这样做的缺点是,您将为这些记录存储两次varchar(MAX)数据,因此需要将更多数据写入数据库,并且将使用更多存储空间,尽管这不是很多如果你只是在讨论一小部分数据,那么就会出现问题。
与往常一样,你把更多的时间和精力放在一边小心翼翼地把东西放回去。