对于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. Spring-事物配置

    Spring框架支持事务管理的核心是事务管理器抽象,对于不同的数据访问框架(如Hibernate)通过实现策略接口PlatformTransactionManager,从而能支持各种数据访问框架的事务 ...

  2. 【URAL 1917】Titan Ruins: Deadly Accuracy(DP)

    题目 #include<cstdio> #include<algorithm> using namespace std; #define N 1005 int n, m, cn ...

  3. yii授权

    ACF (访问控制过滤器) 在你控制器的添加下列的 行为 方法 use yii\filters\AccessControl; class DefaultController extends Contr ...

  4. Oracle自定义函数1

    用户定义函数是存储在数据库中的代码块,可以把值返回到调用程序.调用时如同系统函数一样,如max(value)函数,其中,value被称为参数.函数参数有3种类型. IN 参数类型:表示输入给函数的参数 ...

  5. BZOJ3246 [Ioi2013]Dreaming

    Description Serpent(水 蛇)生活的地方有N个水坑,编号为0,...,N - 1,有M条双向小路连接这些水坑.每两个水坑之间至多有一条路径(路径包含一条或多条小路)相互连接,有些水坑 ...

  6. [IOS Block和delegate的对比]

    原文:http://blog.sina.com.cn/s/blog_9e8867eb0102uykn.html 这篇文章建议和前一篇一起看, 另外先弄清楚IOS的block是神马东东. 委托和bloc ...

  7. Codeforces 85D Sum of Medians

    传送门 D. Sum of Medians time limit per test 3 seconds memory limit per test 256 megabytes input standa ...

  8. include ""与include<>

    在C程序中包含文件有以下两种方法:(1)用符号“<”和“>”将要包含的文件的文件名括起来.这种方法指示预处理程序到预定义的缺省路径下寻找文件.预定义的缺省路径通常是在INCLUDE环境变量 ...

  9. pyenv 以及 virtualenv

    244 pyenv global 3.5.1 245 which python 246 python 247 pip install virtualenv 248 ls 249 pwd 250 ls ...

  10. XSS Filter Evasion Cheat Sheet 中文版

    前言 译者注: 翻译本文的最初原因是当我自己看到这篇文章后,觉得它是非常有价值.但是这么著名的一个备忘录却一直没有人把它翻译成中文版.很多人仅仅是简单的把文中的 各种代码复制下来,然后看起来很刁的发在 ...