对于MS SQL server 数据库,有几个容易让人产生误解的问题,对于这几个问题,即使很多 SQL server DBA 都有错误认识或者认识不充分,所以我想撰文几篇,把这些容易理解错误的问题前前后后深入阐述一下,也希望纠正一下网上对这几个问题的讹传(我也可能有认识不对的地方,欢迎批评指正)。

第一个问题:聚集表的物理顺序问题。这个问题很有迷惑性,因为很多教科书在讲到聚集索引的时候都会出现“聚集索引是按照聚集键的排序顺序物理地存储数据” 类似的说法,因此我们很容易产生以下几种误解:

误解一:“按顺序物理地存储”就是磁盘本身;

误解二:聚集表的页在物理上是顺序的;

误解三:聚集表的页在物理上是顺序的,并且是连续的。

下面我们分别说明上面三种观点确实是误解。

对于误解一,我们必须要了解数据行如何被存储在数据页上。

上图是我从MSDN上截来的,从上图可以看到,在每个数据页的末尾,都有一个“行偏移量”的数组,这个数组记录了每一个数据行的开头在页面中的起始位置,即每行数据开头应该从页头偏移多少个字节。我将上图改了一下,可能更便于正确理解:

我改编的这个图中表示,从这个数据页头偏移96个字节即是第一行数据的开始位置,偏移200字节即是第二行数据的开始位置,偏移300个字节即是第三行数据的开始位置。

下面我们举个实际的例子来说明聚集表的数据在一个数据页上可能的样子。

CREATE TABLE test
(
RowId int not null primary key ,
Column1 char(100)
) INSERT INTO test(RowId,Column1)
Select 1, ' '
Union
Select 2,' '
Union
Select 10,' '

对于上表,数据第一次插入时,这三行数据在数据页上的表现如下:

而如若我再往里面插入如下数据:

INSERT INTO test(RowId,Column1)
Select 7, ' '

因为这个表的RowId 列有聚集索引(primary key 默认创建聚集索引),而数字7大约2,且小于10,那么SQL server 在执行INSERT 操作时,是不是会把RowId = 10 这行数据往下挪呢?显然SQL server 不会这么笨,而只会将RowId = 7这行数据数据附加到RowId = 10 这行数据的后面,然后再修改行偏移量数组,示意图如下:

现在我们应该可以明白:一个聚集索引表数据页上数据行的物理顺序,仅依靠行偏移列表来决定,并不取决于在磁盘上的物理位置。

对于误解二和误解三可以放在一起论述,在论述之前,我们需要先了解一下SQL server 存储引擎中页跟区的概念。
         1. SQL server 中数据存储的基本单位是页。
         2. 区是八个逻辑上连续的页的集合,用来有效的管理页,这也说明,所有的数据页一定属于某个区。
         3. 区分为混合区和统一区。混合区中的页可以被分配给多个数据库对象;统一区中的页一定是被分配给了某一个数据库对象。
         4. SQL server 在为某个数据库对象申请空间时,需要使用GAM,SGAM,PFS 系统页的信息,同时在空间被分配后,也会维护好GAM,SGAM,PFS系统页的息                      。

上面我简单列出了几个要点,更多详细信息大家可以参考下面的链接信息:
         http://msdn.microsoft.com/zh-cn/library/cc280360(v=sql.100).aspx

然后我将列举具体的情况来证明二跟三确实是误解:
         1. 当我们新建一个聚集表,并且往表里插数据,当这个表所占用空间不够8个数据页时,SQL server存储引擎都将从混合区寻找空闲的页面分配给表。而在这个阶段内,很容易出现一个混合区被同时分配给多个数据库对象(最多可达8个数据库对象)。那么,如果我们的聚集表需要再次申请磁盘空间,就很可能在起初的混合区内分配到不连续的页(相对于已分配给这个聚集表的页来说),或者要从另外一个混合区查找空闲页面,这样,是无论如何也保证不了“聚集表的页在物理上是顺序的”,更保证不了“页是连续的”。

2. 如果一个聚集表满8个页,那么,后续所有的空间申请都将分配完整的统一区,这后续的统一区是否可以顺序,或者连续呢? 当然不行,当一个申请空间的动作发出后,存储引擎都会从表所在数据文件的第一个GAM去遍历查找空闲的统一区,如果某个统一区在之前已经分配给某个其它的数据库对象,但当前这个区已经被释放,那么,SQL server 就会将这个空闲的区分配给我们的聚集表,这样也自然保证不了页在物理上的“顺序和连续”;另外,即使SQL server每次都分配从来没有分配给任何数据库对象的区给我们的聚集表,也没有办法保证页在物理上的“顺序和连续”。

3. 如果聚集表出现分页的情况,那么新申请页的页面链的“上一页”会指向被分割的数据页,“下一页”会指向被分割页在分割前指向的下一页。显然,这种情况也没有办法保证页在物理上的“顺序和连续”,而且它是索引碎片情况中的一种。

结论:对于聚集索引表数据行的物理顺序问题,在页与页的角度来看,唯一能指明聚集索引表数据页顺序的是数据页上的页面链表。因为页面链表清楚的指明了本页的上一页,及下一页的页面号分别是啥,而页面号就决定了上一页及下一页的物理位置;如果将眼光缩小到一个数据页的范围内,决定数据行物理位置的因素只有页脚的行偏移量数数组。

(转)SQL server 容易让人误解的问题之 聚集表的物理顺序问题的更多相关文章

  1. c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程

    c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...

  2. SQL Server ->> 深入探讨SQL Server 2016新特性之 --- Temporal Table(历史表)

    原文:SQL Server ->> 深入探讨SQL Server 2016新特性之 --- Temporal Table(历史表) 作为SQL Server 2016(CTP3.x)的另一 ...

  3. 【SQL Server高可用性】数据库复制:SQL Server 2008R2中通过数据库复制,把A表的数据复制到B表

    原文:[SQL Server高可用性]数据库复制:SQL Server 2008R2中通过数据库复制,把A表的数据复制到B表 经常在论坛中看到有人问数据同步的技术,如果只是同步少量的表,那么可以考虑使 ...

  4. 【SQL server初级】数据库性能优化二:数据库表优化

    数据库优化包含以下三部分,数据库自身的优化,数据库表优化,程序操作优化.此文为第二部分 数据库性能优化二:数据库表优化 优化①:设计规范化表,消除数据冗余 数据库范式是确保数据库结构合理,满足各种查询 ...

  5. SQL Server时间粒度系列----第7节日历数据表详解

    本文目录列表: 1.时间粒度有关描述 2.时间维度有关功能函数3.日历数据表 4.日历数据表数据填充 5.总结语 6.参考清单列表   时间粒度有关描述   将该系列涉及到的时间粒度以及分钟以下的粒度 ...

  6. SQL SERVER 中 实现主表1行记录,子表多行记录 整合成一条虚拟列

    表中有这样的记录,简单的主子表,现要想通过left join 语句把两表关联起来 select * from tbl_diary_reback a left join tbl_diary_reback ...

  7. SQL SERVER 判断是否存在并删除某个数据库、表、视图、触发器、储存过程、函数

    -- SQL SERVER 判断是否存在某个触发器.储存过程 -- 判断储存过程,如果存在则删除IF (EXISTS(SELECT * FROM sysobjects WHERE name='proc ...

  8. SQL Server 2012 “阻止保存要求又一次创建表”的更改问题的设置方法

    我们在用SQL Server 2012 建完表后,插入或改动随意列时,提示:当用户在在SQL Server 2012企业管理器中更改表结构时.必需要先删除原来的表.然后又一次创建新表,才干完毕表的更改 ...

  9. sql server几种Join的区别测试方法与union表的合并

    /* sql server几种Join的区别测试方法 主要来介绍下Inner Join , Full Out Join , Cross Join , Left Join , Right Join的区别 ...

随机推荐

  1. Lucene 4.7 --高亮显示

    jar lucene-analyzers-common-4.7.0.jar lucene-analyzers-smartcn-4.7.0.jar lucene-core-4.7.0.jar lucen ...

  2. 【转】Eclipse下导入外部jar包的3种方式

    我们在用Eclipse开发程序的时候,经常要用到第三方jar包.引入jar包不是一个小问题,由于jar包位置不清楚,而浪费时间.下面配图说明3种Eclipse引入jar包的方式.   1.最常用的普通 ...

  3. Treap实现山寨set

    treap插入.删除.查询时间复杂度均为O(logn) treap树中每个节点有两种权值:键值和该节点优先值 如果只看优先值,这棵树又是一个堆 treap有两种平衡方法:左旋&右旋 inser ...

  4. Linux Kernel中获取当前目录方法(undone)

    目录 . 引言 . 基于进程内存镜像信息struct mm_struct获取struct path调用d_path()获取当前进程的"绝对路径" . 基于文件描述符(fd).tas ...

  5. 在纯HTML的静态网页中添加一段统计网页访问量的JAVA Script代码?

    如何在网站上进行流量统计呢,可以找第三方服务网站去注册,但也可以在网站上直接添加代码,只需将以下代码copy到你的网页中,复制到</body>之前就可以啦!是不是很简单啊! <scr ...

  6. jQueryEasyUI DateBox的基本使用

    http://www.cnblogs.com/libingql/archive/2011/09/25/2189977.html 1.基本用法 代码: 1 2 3 4 5 6 7 8 9 10 11 1 ...

  7. jQuery EasyUI datagrid实现本地分页的方法

    http://www.codeweblog.com/jquery-easyui-datagrid%e5%ae%9e%e7%8e%b0%e6%9c%ac%e5%9c%b0%e5%88%86%e9%a1% ...

  8. Recruit Coupon Purchase Winner's Interview: 2nd place, Halla Yang

    Recruit Coupon Purchase Winner's Interview: 2nd place, Halla Yang Recruit Ponpare is Japan's leading ...

  9. TCP的那些事儿(下)

    TCP的那些事儿(下) 这篇文章是下篇,所以如果你对TCP不熟悉的话,还请你先看看上篇<TCP的那些事儿(上)> 上篇中,我们介绍了TCP的协议头.状态机.数据重传中的东西.但是TCP要解 ...

  10. C#设计模式-1、适配器模式(Adapter Pattern)(转载)

    概述 在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的.那么如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同 ...