问题 避免基于递增键创建聚簇索引


我得到了这个提示 mssqlcity.com。但是,我无法理解它的解释。

避免基于递增键创建聚簇索引

例如,如果一个表有代理   整数主键声明为   IDENTITY和聚集索引是   在此列上创建,然后每个   时间数据插入此表中,   行将添加到结尾   桌子。当很多行时   可能会出现“热点”。热的   当许多查询尝试时,会出现“现场”   在同一区域读取或写入数据   同一时间。一个“热点”导致   I / O瓶颈。注意。默认情况下,SQL   服务器为。创建聚簇索引   主键约束。所以,在这   case,你应该明确指定   NONCLUSTERED关键字表示   为...创建非聚集索引   主键约束。

在我阅读之前,我想如果我选择一个本质上是随机的列,那就不正确了,因为这会在添加新行时导致不必要的页面重定位。所以,我认为使用排序列是可取的。

在阅读了这个提示之后,我认为我们并不是真的想要使用直线排序的列作为我们的聚簇索引,因为这些写密集型应用程序会出现I / O瓶颈。

我真的不明白他们正在谈论的I / O瓶颈的原因。他们是说共享同一页面的太多操作会减慢磁盘操作的速度吗?这是怎么发生的?有人可以向我解释一下吗?


12514
2018-03-14 18:07


起源

有提到“新的 SQL Server 2000 功能“这应该让你了解这篇文章的年龄。 - Quassnoi
@Quassnoi呀,我现在得到了JNK的暗示。我认为该建议适用于SQL Server 6.5或更早版本。我用Google搜索并找到了 这个。它说一旦将行级锁定功能添加到SQL Server 7.0中。热点问题解决了。 - Harvey Kwok
sqlpassion.at/archive/2014/04/15/... - Henry


答案:


他们所指的热点不是SQL Server 2005及更新版本中的问题。

使用的是你所有的数据被写入聚集索引的同一区域和磁盘上的相同扇区,这导致一次创建大量脏页(脏页是具有数据页的数据页)已被更改但未提交到磁盘),并且当刷新或检查点运行时,这可能会导致问题。

由于IO架构的变化(根据我的理解),较新的版本不会遇到此行为。


7
2018-03-14 18:14



我明白了,我在热点上做了一些googlging。你似乎是对的。但是,我仍然不明白为什么写很多脏页会导致性能问题。即使它们不在同一扇区,我想我们仍然需要将相似数量的数据刷新到磁盘上。我会做更多的谷歌搜索。 +1,谢谢你的暗示。 - Harvey Kwok


所有现代交易数据库(过去十年中开发的现代手段)都使用事务记录。

这意味着对数据库的所有更改都以顺序方式写入特殊文件(称为事务日志),然后特殊的专用进程会解析此文件并将更改应用于实际数据。这被称为a CHECKPOINT

如果十个线程将十条记录插入到带有的表中 IDENTITY 在列中,引擎将创建十个事务日志记录(由单个进程一个接一个地写入 Log Writer),然后,当它的时间 CHECKPOINT,这些记录将被写入适当的数据页面(也可以通过单个进程调用 Checkpoint)。

由于它们是连续的,很可能,它们将被写入单个数据页中 I/O 操作,并且不会发生页面拆分,因为它们之后没有数据。

如上所述,一个不断递增的密钥上的聚簇索引是 更多 效率高于随机密钥。


4
2018-03-14 18:32





好吧,我之前听过同样的故事。显然这是一个神话。通常建议使用增长的群集主键。所有主要数据库供应商都知道这一点,并减轻了您为避免增长密钥而引用的情况。

也可以看看 https://dba.stackexchange.com/questions/1584/is-avoid-creating-a-clustered-index-based-on-an-incrementing-key-a-myth-from-sq

引用也违背了建议(来自同一页面):

考虑创建代理整数主键(例如,标识)。   每个表必须具有主键(数据库表中行的唯一标识符)。代理主键是具有唯一值但对记录本身没有实际意义的字段,因此用户永远不应该看到或更改代理主键。一些开发人员使用代理主键,其他开发人员使用数据字段作为主键。如果主键由许多数据字段组成且大小很大,请考虑创建代理整数主键。这可以提高查询的性能。


4
2018-03-14 18:13