SQLSERVER的数据页面结构
在论坛里经常有人问到SQLSERVER是怎麽存放基础表数据的,既然不想查MSDN,本人就在这里说一下吧
基础表数据都存放在数据页里面,SQLSERVER存储数据都是按照“页”为单位来存放在磁盘的,SQLSERVER从
磁盘读写数据也是按照 “页” 为单位 一页一页地读取到内存,所以有时候如果数据不能塞满整个数据页,那么
这种情况就叫做:page split 页拆分 或者 “碎片”(详细的在文章结尾会跟大家解释一下因为要先了解SQLSERVR
的数据页面结构才能解释清楚) ,SQLSERVER有时候需要读取两页才能把用户需要找的数据读出来
,如果表加了索引的话可以通过重建索引的方法解决,没有建立索引的话就没有办法了
因为建立了索引的表,表里面的数据是放在B树数据结构的索引页,而不是堆数据结构的数据页
好像说太多了,现在说一下数据页面是怎样存放数据:
每一行数据在数据页面里是怎麽存放的?
结构组成:每个SQLSERVER的数据页面大致分成3个部分:页头,页尾偏移量,数据存储 这3个部分
假设现在有一个表,表的结构是:
CREATE TABLE test(
a INT,
b INT
)
他在1:100这个页面上存储数据(1是数据库的数据文件ID 亦即是FILEID,100 是PAGEID 页面编号)。
这个页面结构大致如下图
在页头部分,会记录页面属性,包括页面编号等,还会记录当前页面空闲部分的起始位置在哪里
这样SQLSERVER在要插入新数据的时候,就能够很快地找到开始插入的位置,而页尾的偏移量
记录了每一条数据行的起始位置。这样SQLSERVER在找每一条记录的时候,就能很快找到不会
把前一条记录和后一条搞混。在图例这一页里现在有两条记录:(1,100)和(2,200)第一条
记录的开始位置是96,第二条记录的开始位置是111,从126开始,是空闲的空间
当页面里的数据行发生变化的时候,SQLSERVER不但要去修改数据本身,还要修改这些偏移量的值,
以保证SQLSERVER能够继续准确地管理数据页面里的每一行
不知道大家明白不? 该睡觉了,加完班很困哦
2012-12-21补充:
开头说了碎片 页拆分,如果有索引的话也叫“索引碎片”,那么这些碎片是怎麽造成的 以及如何避免和修复呢?
造成的原因很简单:当你删除表里一条记录的时候,SQLSERVER会去找这条记录的所在页面
然后删除,当你删除了之后,那么那个数据页面存放的数据就变成不连续的了,这时候就称为“数据碎片”
就是页面存放的数据不连续,当你删除多条记录,而这些记录都在同一个页面,那么就会造成数据塞不满
整个页面,当你插入一条记录的时候,这条记录是不会插入到你上次删除的那条记录的地方的,如果SQLSERVER
的最后一个数据页面(这些数据页面是用双向链表来链接的)有位置就插入去,没有位置就新开一个页面,然后插入
记录
如果存在这些碎片主要两个弊端:
弊端一:SQLSERVER在查找记录的时候要查找多个页面才能找到那条记录(特别使用表扫描执行计划),SQLSERVER按一定顺序
一条一条记录地去找,这样的话本来只需要读取一个页面到内存,SQLSERVER现在需要读取两个页面到内存(特别SQLSERVER
使用表扫描执行计划的时候),会造成内存的使用增大,查找时间增多
弊端二:本来使用一个页面可以存放下连续的数据,现在需要两个页面才能存放下这些数据,造成磁盘空间的浪费,占用额外的
磁盘空间
如何避免和修复:
最好在表上建立一个聚集索引,然后通过重建索引或者重新组织索引的方式使数据重新按照建立索引的那个字段的顺序重新排序
存储,重建索引会把这些数据页面重新排序把没有“塞满数据”的页面重新“塞满”,并有序排列(更详细的大家可以看一下MSDN)
看一下这些数据是如何按聚集索引的方式来有序存放的
MSDN:聚集索引除了可以提高查询性能之外,还可以按需重新生成或重新组织来控制表碎片。也可以对视图创建聚集索引。
聚集索引基于数据行的键值在表内排序和存储这些数据行。每个表只能有一个聚集索引,因为数据行本身只能按一个顺序存储
只能按一个顺序存储是指:当你建立聚集索引或者主键的时候,你有可能在多个列上建立了聚集索引或者复合主键
SQLSERVER只会按照你创建索引的时候的最左一列的字段来排序,只是一列,不是说先按第一列排序,
再按第二列排序,再按第三列排序。。。。。。
这个有很多人会混淆!!!!!!!!!!!!!!!
如果表格上没有聚集索引那么这个问题不能解决,没有聚集索引的表都是堆数据结构的表,就是说数据本身就没有一个排列方式
除非加一个聚集索引,使数据有序排列,非聚集索引也不能解决因为非聚集索引只是在表上加了索引但是数据还是按照“堆”
数据结构来排列的,因为SQLSERVER的页面类型有索引页面,数据页面,LOB页面,行溢出页面,具体大家可以看一下
我之前写的这篇文章:SQLSERVER的表格存储组织结构
http://www.cnblogs.com/lyhabc/archive/2012/09/20/2695818.html
可以参考的MSDN文章:
聚集索引设计指南
http://msdn.microsoft.com/zh-cn/library/ms190639(v=SQL.100).aspx
创建聚集索引
http://msdn.microsoft.com/zh-cn/library/ms186342.aspx
创建非聚集索引
http://msdn.microsoft.com/zh-cn/library/ms179325(v=SQL.100).aspx
非聚集索引设计指南
http://msdn.microsoft.com/zh-cn/library/ms189280.aspx
所以很多书上面都说一个数据量比较大的表最好建立一个聚集索引其实也是有道理的
-------------------------------------------------------------------------------------
2013-8-17 补充:
在正常的数据页上,数据行紧接着页的标头按顺序放置。页的末尾是行偏移量表,对于页中的每一行,每个行偏移表都包含一个条目。
每个条目记录对应行的第一个字节与页首的距离。行偏移表中的条目与页中行的顺序相反