微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SQL Server:在外键上创建索引

如何解决SQL Server:在外键上创建索引

在这里试验的是 DELETE 语句如何在一个非常简单的示例上执行。我目前使用的是 sql Server 2017(我也尝试过 sql Server 2014,结果相似)。

我有两个表:ParentChildChild一个指向 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中的Child)上添加索引是个好主意。但是今天,我在一个有点极端的情况下尝试了 DELETE 的行为 - 但我相信这种情况可能会发生在现实生活中 - (子表中有 4 百万行 Parent_ID=2,只有一行 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。

delete with index on FK

38486782 逻辑读取...不是很大吗?我已经尝试更新统计数据以确保。

    UPDATE STATISTICS Child WITH FULLSCAN

然后再次运行我的查询 => 相同的结果。可能是 IX_Child_Parent_ID 上的索引删除问题?

禁用外键上的索引后,事情变得更好了:

表“孩子”。扫描计数1,逻辑读202233,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

delete without index on FK

注意:sql Server 建议为 FK 创建索引。

202233 逻辑读取听起来好多了……至少对于 Parent_Id=2 的特定情况。

问题是:为什么 sql Server 使用索引而不选择聚集索引扫描方法,当它知道Parent_ID = 2 大约有 4 000 000 行时?或者它可能不知道?统计数据不是应该“帮助”sql Server 了解此类信息吗?

我可能遗漏了一些东西。

(我已经仔细检查过,在创建索引后,统计数据 - 似乎 - OK:

stats

解决方法

出于删除的目的和您拥有的数据的基数,如您所见,parent_id 上的索引没有用处。

如果您知道需要删除 99% 的行,那么出于多种原因,这样做是非常低效的,尤其是事务日志的增长。

您执行的每个语句都是原子的,并且是它自己的隐式事务,如果删除在中途失败,即断电,SQL Server 需要能够回滚未完成的删除,为此它使用事务日志,所以所有被删除的行都会命中事务日志。

在这种情况下,将要保留的行插入到新表中,删除原始表,然后将新表重命名为原始表,性能会更高;您还可以编写来自原始表的索引/约束的脚本并将它们应用到新表。

如果删除大部分行但少于表的 50%,其他建议是将作业拆分为批次并一次删除

通常可以帮助在表上创建一个 View 选择要删除的 top n 行,按特定的 排序,然后从视图中删除。

,

也许我在这里找到了答案:https://stackoverflow.com/a/3650886

看起来这是预期的行为,问题实际上是更新索引(在我的情况下为 IX_Child_Parent_ID)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。