页分裂会显著降低索引插入性能,尤其在聚集索引尾部插入不连续键值时最明显;其发生于8KB数据页满载后需插入新记录却空间不足时,引擎将约一半数据移至新页并调整指针,伴随日志写入、锁升级、latch争用及可能的向上分裂。

页分裂会显著降低索引插入性能,尤其在聚集索引的尾部插入不连续键值时最明显。
页分裂是怎么发生的
SQL Server(及其他主流关系型数据库)以固定大小的数据页(通常8KB)为单位存储数据。当一个已满的页需要插入新记录,而该记录无法放入现有空间时,数据库引擎会触发页分裂:将原页约一半数据移到新分配的页中,再调整页间指针(如聚集索引的双向链表或B+树父子节点关系),确保逻辑顺序不变。
这个过程不只是“复制+移动”,还涉及日志写入、锁升级(常升至页面级或更高)、latch争用,以及索引层级可能的向上分裂(如根页或中间页分裂),带来明显开销。
哪些插入场景最容易引发页分裂
- 随机主键插入:如使用NEWID()生成的GUID作为聚集索引键,新行几乎总需插入到中间位置,导致频繁分裂
- 时间倒序插入:例如按DESC创建的datetime字段做聚集索引,新订单时间早于已有数据,插入点不在末尾
- 填充因子设置过高:FILLFACTOR = 100(默认)意味着页初始就填满,毫无预留空间,任何插入都可能立即触发分裂
- 变长字段大量更新增长:UPDATE使行变大,原页放不下,也可能间接引发页拆分(称为“内部分裂”)
如何缓解页分裂对插入性能的影响
- 选用递增键作为聚集索引:如IDENTITY、SEQUENCE或newsequentialid(),保证新行总追加到索引末端,避免定位查找和中间分裂
- 合理设置FILLFACTOR:对写多读少的表,可设为70–85,预留空间容纳后续插入;注意该值仅在索引重建/重组时生效,不会动态维持
- 定期维护索引:通过ALTER INDEX ... REBUILD或REORGANIZE清理碎片、重排页顺序、回收空间;对高并发写入表建议结合统计信息更新一起执行
- 考虑非聚集主键 + 单独聚集索引:若业务必须用GUID主键,可将其设为UNIQUE CONSTRAINT(非聚集),另建含递增列的聚集索引,兼顾查询与写入效率
怎么确认当前是否存在严重页分裂
可通过系统视图查看页级碎片和分裂统计:
-- 查看索引碎片率(重点关注avg_page_space_used_in_percent 和 page_count)
SELECT * FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('Orders'), NULL, NULL, 'DETAILED');
-- 查询页分裂等待(间接指标)
SELECT * FROM sys.dm_os_wait_stats WHERE wait_type IN ('PAGEIOLATCH_UP', 'PAGELATCH_EX');
持续出现高PAGELATCH_EX等待(尤其是集中在聚集索引页),配合高平均碎片率(>30%)和低页空间使用率(











