【发布时间】:2021-07-09 03:49:52
【问题描述】:
我在这里试验的是 DELETE 语句如何在一个非常简单的示例中执行。我目前正在使用 SQL Server 2017(我也尝试使用 SQL Server 2014,结果相似)。
我有两张桌子:Parent 和 Child。 Child 有一个指向 Parent (Parent_ID) 的外键。
家长:
Parent_ID Name
-----------------------
1 P1
2 P2
孩子:
Child_ID Parent_ID Data
-----------------------------
1 1 P1C1
2 2 P2C1
3 2 PPPPCCCC
4 2 P2C1
5 2 PPPPCCCC
(around 4 million more rows with Parent_ID=2)
我一直认为在外键上添加索引(Parent_ID in Child 这里)是个好主意。但是今天,我在一个有点极端的情况下尝试了 DELETE 的行为 - 但我确信这种情况可能会发生在现实生活中 - (在 Child 表中有 Parent_ID=2 的 400 万行,Parent_ID= 只有一行1).
如果我尝试删除 Parent_ID = 1 的行,它看起来不错:它足够快,使用了索引,逻辑读取量似乎还不错(12 次逻辑读取:我我不是专家,不知道对于这么少量的数据是否真的可以)。
现在这是我不明白(也不喜欢)的地方:
我尝试删除 Child 中 Parent_ID=2 的所有记录:
BEGIN TRAN
DELETE FROM child
WHERE parent_id = 2
ROLLBACK TRAN
IO 统计显示(对于 DELETE):
表“孩子”。扫描计数 1,逻辑读取 38486782,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
38486782 逻辑读...不是很大吗?我已经尝试更新统计数据以确保。
UPDATE STATISTICS Child WITH FULLSCAN
然后再次运行我的查询 => 相同的结果。问题可能是 IX_Child_Parent_ID 上的索引删除?
禁用外键索引后,情况好多了:
表“孩子”。扫描计数 1,逻辑读取 202233,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
注意:SQL Server 建议为 FK 创建索引。
202233 逻辑读取听起来好多了……至少对于 Parent_Id=2 的特定情况。
问题是:为什么当SQL Server 知道 Parent_ID = 2 大约有4 000 000 行时,它使用索引而不选择聚集索引扫描方法?或者它可能不知道?难道统计数据不应该“帮助”SQL Server 了解这类信息吗?
我可能错过了什么。
(我已经仔细检查过,在创建索引后统计数据 - 似乎 - 正常:
【问题讨论】:
-
(注:评论自己)也许这是一个愚蠢的案例,一切都很正常......但我真的很乐意得到大师们的一些建议^^
标签: sql-server indexing foreign-keys