我有一个用于存储人员的表格,并希望选择该人未被标记为"已删除"的位置。我在ID列(PersonID
)上有一个聚簇主键。
'已删除' column是DATETIME
,可以为空,并在删除时填充。
我的查询如下:
SELECT *
FROM dbo.Person
WHERE PersonID = 100
AND Deleted IS NULL
这张桌子可以增加到大约40,000人 我是否应该有一个涵盖Deleted标志的索引?
我也可以查询以下内容:
SELECT *
FROM Task t
INNER JOIN Person p
ON p.PersonID = t.PersonID
AND p.Deleted IS NULL
WHERE t.TaskTypeId = 5
AND t.Deleted IS NULL
任务表估计约为150万行。
我想我需要一个涵盖两个表上的pk和已删除标志的文件?即(Task.TaskId, Task.Deleted)
和(Person.PersonID, Person.Deleted)
?
我调查索引重新考虑的原因是由于复杂程序中发生了许多死锁。我希望减少选择/写入/更新时锁定的行数,并获得性能提升。
答案 0 :(得分:2)
由于您使用的是SQL Server 2008,因此最快的查询可能就是使用过滤索引。在类型为Deleted
并且可以为空的DATETIME
列中,您可以尝试使用此索引:
CREATE NONCLUSTERED INDEX Filtered_Deleted_Index
ON dbo.Person(Deleted)
WHERE Deleted IS NOT NULL
这将为您提供上面列出的两个用例中的最小有效集(用于查询dbo.Person
以及加入Tasks
)。
答案 1 :(得分:1)
你的直觉(一般来说)声音 - 包含查询所需的所有列的索引称为覆盖索引,在这种情况下需要:
CREATE INDEX Person_PersonID_Deleted ON Person(PersonID, Deleted);
通过添加Deleted
列,您不太可能在索引查找方面获得很多性能优势,因为(通常)忽略搜索null
,但拥有这些索引意味着可以绕过访问表完全用于Person
。
你也可以尝试创建:
CREATE INDEX Task_TaskTypeId_Deleted ON Task(TaskTypeId, Deleted);
将避免访问标记为“已删除”的Task
行,然后只会访问未删除的行Task
。但是,如果您的大多数Tasks
未已删除,我不会理会此索引。
值得尝试各种索引组合,看看哪种组合能产生最佳结果。
答案 2 :(得分:1)
由于主键是<input type="checkbox" id="a1" style="display: none;" />
<label class="checkmarklabel" for="a1"></label>
:checked + .checkmarklabel:before {
/* put the required CSS for your font's checkmark here */
}
,因此在PersonID之后添加带有额外列的另一个索引将不会提高索引的“可选择性”,尽管可能会阻止需要通过rowid查找记录以便对{{{{{ 1}}。只有3%的记录被过滤,这没什么,所以不要在PersonID
上创建另一个索引。
至于deleted
表,它在很大程度上取决于Person
的可选择性,即有多少记录符合标准。通常,如果选择了超过20%的记录,则顺序搜索(全表扫描)比使用行查找的索引扫描更快。对于数据分布非常大的非常大的表(例如,物理上每隔10条记录被选中),性能阈值低于10%。
因此,如果超过10-20%的任务记录是类型5,并且只删除了3%的记录,则没有索引可以提高性能,因为最快的访问计划可能是两个全表扫描的合并连接。