Dav*_*ims 4 sql-server-2008 sql-server data-pages database-internals
几天来,我一直在工作中的网络上进行挖掘,试图弄明白 DBMS(SQL Server 2008 R2 和其他)如何如此快速地将一列添加到大表的末尾。
在高层次上,您可以认为:我可以在末尾放置一个指向新列的指针。但是,在页面级别上,数据页面不是填充了单个记录吗?添加一列是否意味着每个已经满的页面都需要拆分?
即使页面未满,也需要大量数据处理才能将该列添加到每条记录的末尾,更新所有插槽数组,然后通过任何现有索引和/或 IAM 和 GAM 页面级联所有指针更改?
我唯一能想到的是,所有新的列数据都被添加到新的页面中,没有记录的其余部分,并且在整个表树结构中添加指针以引用新的列页面。然而,这似乎会破坏空间局部性。如果是这样,即使我们没有特别请求,DBMS 是否会在幕后处理数据REBUILD
?
我正在谈论带有页面的 DBMS 内存管理的位级别,并询问 DBMS 如何能够如此快速地将一列(允许或不允许 NULL 值)添加到一组现有记录中,即使这些记录已经作为一组存在数据页中的位。
DBMS(SQL Server 2008 R2 和其他)如何如此快速地将一列添加到大表的末尾。
好吧,这里有一个错误的假设,即添加新列总是很快完成。这不是一个真实的陈述。
现在,当添加一个允许NULL
s的列时,随着 Table 定义的元数据得到更新,这可以快速完成,但NULL
在那一刻没有物理添加到数据页。SQL Server 可以返回正确NULL
的查询,因为“值”是什么在逻辑上是显而易见的。插入或更新行时,写入数据页的记录确实包括NULL
(对于固定长度的列,除非该SPARSE
选项用于新列或在聚集索引上启用了数据压缩)。但是没有更新的其余行在NULL
索引之前不会物理添加REBUILD
。
但是,在NOT NULL
SQL Server 2012 之前添加标记为 的列时(即使如此,仅当新值是运行时常量时),那么实际值在那个时刻被物理写入数据页,并且该操作可以花费 looooooooooong 时间,具体取决于表中的行数和/或数据量。您可以找到大量关于尝试解决此问题的问题和文章,因为包含大量 GB 数据和/或数亿行的表可能需要数小时才能添加新NOT NULL
列。
然后是 SQL Server 2012(仅限企业版,也意味着开发人员版)中真正精彩的新功能,添加NOT NULL
具有默认值的新列可以是即时的、仅限元数据的操作,就像添加标记为的列一样NULL
. 唯一的警告是数据类型不是 LOB(例如MAX
-types、XML
等)或基于 CLR 的类型,并且该值是运行时常量(即主要是文字值)。类似的东西NEWID()
不会是即时的,因为每行需要不同的值。但是对于运行时常量的值,SELECT
操作可以通过查看DEFAULT
给出逻辑上显而易见的值的元数据轻松获得正确的值。
ALTER TABLE的 MSDN 页面,在Locks and ALTER TABLE部分(在“Adding NOT NULL Columns as an Online Operation”下),讨论了这种行为。
归档时间: |
|
查看次数: |
119 次 |
最近记录: |