一直以来,很多文章或书籍都会提到数据库在对数据做增删修都会因为数据异动导致Page Splits的产生。 一旦过度的分割就会提高所谓的逻辑片段,而要降低逻辑片段就得对数据表或索引做Rebuild或Reorganize,今天心血来潮突然想LAB看看SQL对Page Splits的运作原理为何,所以简易做个实验。

下图中我创建数据库DB1,在数据库创建一个数据表Tb1,每一列为2004个Bytes,这样一来每个Page最多只能存放4笔数据(一个Page为8060个Bytes)。 我用Tb1的id字段来当丛集索引,并写入了16笔纪录。

SQL存储的最小单位是Page,但SQL在给空间时会一次配置8个Page,也就是一个Extents(64K Bytes)。 而我Insert了16笔资料会占了4个Page再加上1个Page用来纪录Index纪录的中继层级页面,所以这个Extents也就用掉了5个页面,配置如下图所示。

接下来我们用DBCC IND(‘DB1’,‘Tb1’,1)指令来看一下Tb1的页面配置状况。 下图中红色区块是存储数据的页面,而蓝色的块页面则是放索引的页面,所以通过下表我们可以看到该Table目前用了5个Page,Page编号是 232 ~ 236 (注意同一个Extents其Page是连号的)。 而该数据表的数据排序是232→234→235→236 ,如下图左边中我画上的编号顺序。 页面顺序可以从表中的NextPagePID及PrevPagePID的字段内容来排序。****

接下来我们用**DBCC PAGE(‘DB1’,1,233,3)**指令来看看纪录Index纪录的中继层级页面233里存了什么。 如下图所示,他存了4笔资料分别记录了丛集字段id(1、2、3、4)存放的页面位置。

接下来我故意要塞入一笔**id=1 name=‘Cary’**的资料进资料表,由于id=1所以可以知到这笔资料会被塞入存放id=1的页面中。 但由于该页面已满,无法写入第5笔数据,为了写入数据势必要透过Page Splits来取得空间。****

下圖中我塞入一筆 id=1 name=‘Cary’ 的資料後馬上檢視該Table的Page配置,結果多了一個 Page 237 出來如下圖中紅色區塊。透過NextPagePID及PrevPagePID的欄位內容來重新排序一下。發現順序變為232→237→234→235→236 新增加的頁面順序卻擺在第二順位。

重新檢視存放索引資料的 Page 233 頁面,可以發現多了一筆紀錄。該紀錄顯示id=1的值存放頁面是Page 237,如下圖紅色區塊區。

接下來我們看看這一頁新增的頁面裡到底存了什麼內容,我們用指令 DBCC PAGE(‘DB1’,1,237,3) 來檢視頁面資料。如下圖所示該頁面存了3筆資料,剩餘空間2033 Bytes,資料存放的皆是id=1的內容。我們發現id=1 name=Cary的資料也是存放在這一個頁面。****

根據上述資料,我們可以知道目前該Table的資料配置如下圖,id=1的資料有5筆並分配在兩個頁面內

接下來我再塞入一筆 id=2 name=‘Cary’ 的資料進資料表,由於id=2所以可以知到這筆資料會被塞入存放id=2的頁面中。但由於該頁面也是滿的,無法寫入第5筆資料,為了寫入資料勢必也要透過Page Splits來取得空間。****

下圖中我塞入一筆 id=2 name=‘Cary’ 的資料後馬上檢視該Table的Page配置,結果多了一個 Page 238 出來如下圖中紅色區塊。透過NextPagePID及PrevPagePID的欄位內容來重新排序一下。發現順序變為 232→237→234→238→235→236 新增加的頁面順序卻擺在第四順位。

重新檢視存放索引資料的 Page 233 頁面,可以發現多了一筆紀錄。該紀錄顯示id=2的值存放頁面是 Page 238,如下圖紅色區塊區。

接下來我們看看這一頁新增的頁面裡到底存了什麼內容,我們用指令 DBCC PAGE(‘DB1’,1,238,3) 來檢視頁面資料。如下圖所示該頁面存了3筆資料,剩餘空間2033 Bytes,資料存放的皆是id=2的內容。我們發現id=2 name=Cary的資料也是存放在這一個頁面。

根據上述資料,我們可以知道目前該Table的資料配置如下圖,id=1的資料有5筆並分配在兩個頁面內,id=2的資料也有5筆也分配在兩個頁面內

接下來我要塞入4筆 id=5 的資料到Table中,這樣一來一個 Extents(8個Page) 都會被吃滿。製造完這樣的環境後我們一樣再來測試Page Splits。

Insert Into 4筆id=5 name=Rock的資料進Tb1資料表。

檢視一下Tb1資料表的頁面配置,如下圖所示 Page 232 到 Page 239 共8個頁面都被使用到了(下圖紅色區塊)。

此刻我們用 DBCC SHOWCONTIG(Tb1,1) 來檢視資料表片段狀況。可以看見該Table目前 資料頁數是7頁及Extents數是1,由於Splits多次所以邏輯掃描片段是71%(資料頁面7,因不連號而來回了5次,5/7=0.71428左右)。

當整個Extents沒有空間再應付Page Splits的需求時,接下來我再塞入一筆 id=3 name=‘Cary’ 的資料進資料表,由於id=3所以可以知到這筆資料會被塞入存放id=3的頁面中。因為整個Extents是滿的,接下來的空間配置SQL會如何做呢?****

下圖中我塞入一筆 id=3 name=‘Cary’ 的資料後馬上檢視該Table的Page配置,結果多了一個 Page 256 出來如下圖中紅色區塊。透過NextPagePID及PrevPagePID的欄位內容來重新排序一下。發現順序變為 232→237→234→238→235→256→236→239 新增加的頁面序號跳到 256,順序擺在第6順位。

重新檢視存放索引資料的 Page 233 頁面,可以發現多了一筆紀錄。該紀錄顯示id=3的值存放頁面是Page 256,如下圖紅色區塊區。

接下來我們看看這一頁新增的頁面裡到底存了什麼內容,我們用指令 DBCC PAGE(‘DB1’,1,256,3) 來檢視頁面資料。如下圖所示該頁面存了3筆資料,剩餘空間2033 Bytes,資料存放的皆是id=3的內容。我們發現id=3 name=Cary的資料也是存放在這一個頁面。****

由於第一個Extents的最後一個Page編號是239但是這一個新的Page不是接續的給Page 240而是跳號到256,由此可以判斷兩個Extents是不接續的。下圖是簡易的顯示目前Table的頁面配置。

我們透過 sys.dm_db_database_page_allocations 這個DMV可以更清楚的看見Extents跟Pages彼此之間的關聯。

這時我們再用 DBCC SHOWCONTIG(Tb1,1) 來檢視資料表片段狀況。可以看見該Table目前資料頁數是8頁及Extents多了1個變成2了,由於Splits多次所以邏輯掃描片段是87.5%(資料頁面8,因不連號而來回了7次,7/8=0.875左右)。至於範圍掃描片段變成50%則是因為目前有2個Extents但第一個跟第二個Extents是跳號的不接續的,所以1/2=0.5就是50%囉。****

这真的是一个又臭又长的LAB,希望大家看得懂Rock在写什么。 透过简易的LAB后我们可以知到每一次的Splits ,SQL会先取得一个空的新Page然后将部分数据改写到新的Page去,然后改写页面的顺序指标。 当这样的动作很频繁时不仅耗费系统资源且会造成数据片段严重,当资料页面不连续时也会影响Disk IO读取的速度。 所以如何减少Page Splits的发生在数据表设计时就需考虑进去,例如索引(丛集跟非丛集)字段的选择,还有FillFactor设定值等,片段率达到多少时就Rebuild或Reorganize。

补充 : Page Splits时SQL会尽量拆分为50% 50%,以下是找到的一段说明。

The page will split *either* as close to 50/50 as it can (the general case) or at the insertion point, depending on the distribution of index key values on the splitting page.

只是浅谈MS SQL Server的Page Splits运作原理相关推荐

  1. 浅谈实现SQL Server远距离异地容灾

    浅谈实现SQL Server远距离异地容灾 SQL Server 从2012 推出 SQL Alwayson 以来,使我们对SQL Server数据库容灾产生翻天覆地的变化. 其优点很明显 1.不依赖 ...

  2. freebsd php 编译 mysql sql2005_问下:Freebsd下用php连接ms sql server

    你的位置: 问答吧 -> PHP -> 问题详情 问下:Freebsd下用php连接ms sql server 大家都怎么连接的,,,效率如何? 作者: james.liu 发布时间: 2 ...

  3. 聚焦索引与非聚焦索引及其查询效率 (MS SQL SERVER)

    郑重声明:本文转自互联网,出处不明,无法注明出处,在此对笔者表示感谢. 随着"金盾工程"建设的逐步深入和公安信息化的高速发展,公安计算机应用系统被广泛应用在各警种.各部门.与此同时 ...

  4. PHP(2):PHP读取MS Sql Server 2014数据库数据

    前面使用VBS将Excel数据写入到了Ms Sql Server 2014的数据库,现在要将记录显示出来,本来打算用IIS+ASP.net,可是9月份安装好Apache+PHP后一直没有写过PHP代码 ...

  5. MS SQL Server数据库修复利器—D-Recovery For MS SQL Server数据恢复软件

    微软的SQL Server 数据库最常用的有两种类型的文件: 1.主要数据文件,文件后缀一般是.MDF: 2.事务日志文件,文件后缀一般是.LDF. 用户数据表.视图.存储过程等等数据,都是存放在MD ...

  6. springboot + vue + nginx+ MS SQL Server项目部署方法

    一.nginx 1.1 安装 自行搜索nginx进入官网nginx: download选择相应的版本即可. 直接解压到自定义目录: 双击运行nginx.exe,出现终端一闪而过,浏览器输入localh ...

  7. MS SQL Server和MySQL区别

    - 最近在做MS SQL Server转换成MySQL的工作,总结了点经验,跟大家分享一下.同时这些也会在不断更新.也希望大家补充. 1 MySQL支持enum,和set类型,SQL Server不支 ...

  8. iBatis自动生成的主键 (Oracle,MS Sql Server,MySQL)【转】

    iBatis的sqlMap配置文件的selectKey元素有个type属性,可以指定pre或者post表示前生成(pre)还是后生成(post). Oracle设置 Xml代码   <!-- O ...

  9. MS sql server和mysql中update多条数据的例子

    1. MS sql server中使用动态的表名:declare @tableName nvarchar(160) set @tableName = 't_stat_all' declare @sql ...

最新文章

  1. spring中controller与jsp之间的那些事儿
  2. 面向对象理论(6)-Interface Programming-[A]
  3. animate中使用HTML5,animate.css怎么使用?
  4. vue seo关键词设置_SEO关键词优化排名的几个技巧
  5. SSIS package 更新 variable
  6. java语言程序设计第六章答案_Java语言程序设计(邵丽萍编著)第六章.doc
  7. 当面试官问你如何进行性能优化时,你该这么回答(一)
  8. linux——服务器与客户端实现聊天功能
  9. docker 数据卷 mysql_Docker 入门教程(五)数据卷 Volumes
  10. iphone socket讲解
  11. hough变换理解 原理 步骤
  12. 关于adb驱动的安装
  13. 我的×××面——深信服面试全记录
  14. python当前时间获取_python 当前时间获取方法
  15. CVPR21-无监督异常检测《CutPaste:Self-Supervised Learning for Anomaly Detection and Localization》
  16. 《黑白团团队》第八次团队作业:Alpha冲刺 第一天
  17. 微信开发_网页授权获取用户的基本信息
  18. CSS基础————千本樱滑落的瞬间
  19. FlinkJob提交流程
  20. 考研英语阅读理解做题技巧(4):态度题

热门文章

  1. linux上无法发送163邮件,如何在linux中发送邮件,使用163邮箱发信。
  2. googletest 学习笔记
  3. Delphi 热键 使用WIN作为热键的组合键 给程序增加快捷键
  4. pytorch中的所有随机数(normal、rand、randn、randint、randperm) 以及 随机数种子(seed、manual_seed、initial_seed)
  5. matlab 程序文件,MATLAB程序文件
  6. 巴黎报纸对拿破仑的描述
  7. 大学英语(第三册)复习(原文及全文翻译)——Unit 7 - The Shelter(防空洞)
  8. 大数据文字游戏_移动的大数据指南:千字以内的文章传播率最高
  9. Java:使用Java调用打印机进行打印(JPG、PDF和Word三种文件格式)
  10. windows统计各个目录的大小