前言: 本文对这篇博客Clustered Tables vs Heap Tables 的翻译, 如有翻译不对或不好的地方,敬请指出,大家一起学习进步。

问题描述

创建一个新表时,一个非常重要的设计原则就是创建还是不创建聚集索引的决定。没有聚集索引的表被称为堆,拥有聚集索引的表叫聚集索引表。 聚集索引表比堆表拥有一些好处(优势),比如聚集索引表是基于聚集索引键顺序存储的,正因为如此,所以通过聚集索引可以快速查找某一行;可以通过重建聚集索引重新组织数据。当你对表进行INSERT、UPDATE、DELETE等操作时可能会使物理数据变得碎片化,这种碎片化可能会导致你浪费大量数据库存储空间,因为本来可以存储在一页的数据,需要存储在多个数据页上(Pages),那么,我们该怎么做呢?

解决方案

我们要解决的首要问题是发生在数据库正常活动中的碎片。你的表是否拥有聚集索引 将决定您是否可以在数据库物理层面很容易的解决碎片化问题。因为堆或聚集索引决定你表数据的物理存储,每个表要么拥有一个聚集索引或没有一个聚集索引,所以每个表要么是一个堆或聚集索引表。

让我们来看看一个堆表和聚集索引表之间的差异:

HEAP

数据存储没有任何特定的顺序。

不能快速的找到特定数据,除非也有非聚集索引。

数据页之间没有指针关联,所以顺序访问需要重新返回到索引分配映射(IAM)页

既然没有聚集索引,所以不用额外的时间去维护聚集索引。

既然没有聚集索引,所以不用额外的空间去存储聚集索引树。

堆表的索引在sys.indexes目录视图的记录的index_id字段值为0

Clustered Table

数据存储基于聚集索引键顺序存储。

如果查询时使用聚集索引列,数据可以基于聚集索引键快速检索到。

数据页之间有指针链接,可以更快速的顺序访问。

当INSERT、UPDATE、DELETE操作时,需要额外的时间维护聚集索引。

需要额外的空间存储聚集索引树。

聚集索引表在sys.indexes目录视图的记录的index_id值为1.

所以,基于以上你可以看到有一个表是否具有聚簇索引将决定表的一些根本性的不同之处。

碎片化问题

所有的表都会发生的一个问题就是碎片化的问题。根据不同的操作,比如删除,插入和更新,您的堆表和聚集索引表将会变得越来越碎片化。碎片化很多时候取决于INSERT、UPDATE、DELTE这类操作,以及用作聚集索引的键。

如果您的堆表只有INSERT操作,你的表不会变得碎片化,因为只有新的数据写入。

如果您的聚集索引键是连续的,比如一个自增字段。并且对该表你只有INSERT操作,这同样也不会变得碎片化,因为新的数据总是写在聚簇索引的后面。

但是,如果你的表是一个堆或聚集表,并有大量的插入,更新和删除操作,数据页碎片化可能会变得越来越严重。这不仅会导致浪费额外的空间,而且需要读取额外的数据页来满足查询。

当一个表在堆上创建,SQL Server不会强迫在那个新数据页(New Page)写入数据。每当新的数据写入时,该数据总是写在表的末端,或者分配给该表中的下一个可用的页面上。当数据被删除时,数据页上的空间释放出来,但它不重复使用,因为新数据总是写入到下一个可用的页面。

具有聚簇索引,根据索引键,新的记录可能会被写入到现有的页面,这些页面可能存在的空闲的空间或者有可能需要分割成多个页面的页面。以便插入新的数据。删除时会发生同样的问题时,与一个堆对比,但是这些空闲间可以再次使用,如果数据需要插入到具有可用空间的现有页面中的一个。

所以,基于以上叙述 ,你的堆表可能变得比你的聚集表更加支离破碎。

查看碎片化
要确定您的聚集索引表或堆表是否碎片化,你要么通过运行DBCC SHOWCONTIG(SQL SEREVER 2000或SQL SEREVER 2005)查看,或使用新的DMVsys.dm_db_index_physical_stats(SQL SERVER 2005 以及以后版本)。这些命令能让你查看表中可能存在的碎片化问题。如需更多相关信息,看看以前的这篇文章提示:SQL Server 2000 to 2005 Crosswalk - Index Rebuilds.

解决碎片化

聚集索引表


    解决聚集索引的碎片化可以很容易地通过重建或重新组织你的聚集索引来完成。这表现在这之前的提示: SQL Server 2000 to 2005 Crosswalk - Index Rebuilds

堆表

对于堆表来说,这个不太容易的。您可以采取以下不同的方法来解决碎片问题:

  1. 对堆表创建一个聚集索引
  2. 创建一个新的堆表,并根据某种顺序将旧表中的数据插入到新表
  3. 导出数据,截断表并导入数据返回到表

附加信息

当你通过企业管理器或Management Studio创建一个新表并在新表中指定一个主键,管理工具会自动为其创建一个聚集索引,但可以被重写。当通过脚本创建一个新表时,你需要明确指定创建聚集索引。所以,正是由于主键关系,你大部分的表将会拥有一个聚集索引,但如果创建表时,你不指定一个主键或建立聚集索引,该表的数据将被存储为一个堆。

 

下一步

维持表和索引的碎片化在控制范围内是保持数据库最佳性能的一个关键过程。现在你可以明白一个堆与聚集索引表在解决碎片化上的不同,看看你的表结构,看看你需要解决这些问题。

即使对所有表一个星期做一次索引重建,你的堆表是永远不会解决琐碎化问题的,所以你需要想出另一种策略来处理堆表的碎片问题。

一起来看看这些相关技巧:

SQL Server 2000 to 2005 Crosswalk - Database Fragmentation.

SQL Server 2000 to 2005 Crosswalk - Index Rebuilds.

基于上述论证,似乎所有的表都应该有一个聚集索引。在大多数情况下是这样,但也可能由于某种原因,你不希望有一个聚集索引。一个原因可能是该表只有INSERT操作,例如一个日志记录的表。但是毫无疑问,有聚集索引一定好过没有聚集索引

[翻译] 聚集索引表 VS 堆表的更多相关文章

  1. 索引深入浅出(4/10):非聚集索引的B树结构在聚集表

    一个表只能有一个聚集索引,数据行以此聚集索引的顺序进行存储,一个表却能有多个非聚集索引.我们已经讨论了聚集索引的结构,这篇我们会看下非聚集索引结构. 非聚集索引的逻辑呈现 简单来说,非聚集索引是表的子 ...

  2. SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析

    在SQL SERVER的查询语句中使用OR是否会导致不走索引查找(Index Seek)或索引失效(堆表走全表扫描 (Table Scan).聚集索引表走聚集索引扫描(Clustered Index ...

  3. SQL Server 堆表与栈表的对比(大表)

    环境准备 使用1个表,生成1000万行来进行性能对比(勉强也算比较大了),对比性能差别. 为了简化过程,不提供生成随机数据的过程.该表初始为非聚集索引(堆表),测试过程中会改为聚集索引(栈表). CR ...

  4. SQL Server性能优化(8)堆表结构介绍

    一.表结构综述 下图是SQL Server中表的组织形式(其中分区1.分区2是为了便于管理,把表进行分区,放到不同的硬盘数据文件里.默认情况下,表只有一个分区.).表在硬盘上的存放形式,有堆和B树两种 ...

  5. SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析 (转载)

    在SQL SERVER的查询语句中使用OR是否会导致不走索引查找(Index Seek)或索引失效(堆表走全表扫描 (Table Scan).聚集索引表走聚集索引扫描(Clustered Index ...

  6. SQL SERVER大话存储结构(2)_非聚集索引如何查找到行记录

              如果转载,请注明博文来源: www.cnblogs.com/xinysu/   ,版权归 博客园 苏家小萝卜 所有.望各位支持!      1 行记录如何存储     这里引入两个 ...

  7. 索引深入浅出(5/10):非聚集索引的B树结构在堆表

    在“索引深入浅出:非聚集索引的B树结构在聚集表”里,我们讨论了在聚集表上的非聚集索引,这篇文章我们讨论下在堆表上的非聚集索引. 非聚集索引可以在聚集表或堆表上创建.当我们在聚集表上创建非聚集索引时,聚 ...

  8. SQL Server 索引和表体系结构(聚集索引)

    聚集索引 概述 关于索引和表体系结构的概念一直都是讨论比较多的话题,其中表的各种存储形式是讨论的重点,在各个网站上面也有很多关于这方面写的不错的文章,我写这篇文章的目的也是为了将所有的知识点尽可能的组 ...

  9. SQL Server索引 (原理、存储)聚集索引、非聚集索引、堆 <第一篇>

    一.存储结构 在SQL Server中,有许多不同的可用排列规则选项. 二进制:按字符的数字表示形式排序(ASCII码中,用数字32表示空格,用68表示字母"D").因为所有内容都 ...

随机推荐

  1. 使用免费组件view pdf 文档

    “Is there any way to view PDF files in a Winforms tool?” 这个是我在技术论坛上发现的一个老外求助的帖子,然后看到别人回复的帖子中建议了一个免费的 ...

  2. 不行,受不了了,我要记录下这个 bug

    我们在使用 java 中使用线程 Thread 的时候,在 run(){  } 里面的如果要传递参数给函数,一般,编译系统都会提示我们,要将这个参数尽可能地设置为 final,即常量,一旦定义就不能再 ...

  3. 【JUC】JDK1.8源码分析之SynchronousQueue(九)

    一.前言 本篇是在分析Executors源码时,发现JUC集合框架中的一个重要类没有分析,SynchronousQueue,该类在线程池中的作用是非常明显的,所以很有必要单独拿出来分析一番,这对于之后 ...

  4. 到处都是坑的微信支付V3

    业务需要一个在微信上能付款的功能,于是乎想到了最普遍的支付宝,坑爹的是T与A是水火不容啊,默默的还是接微信支付吧,没想到从此掉进了连环坑…… 网上写微信支付接口的还是很多,PHP官方有(鄙视源码作者, ...

  5. 基于Hadoop生态技术构建阿里搜索离线系统

    一.计算平台架构 平台架构 集群规模 集群特点 二.支撑的搜索业务 搜索业务 处理流程 三.YARN计算平台 iStream计算模型 Schedule改进 AppHistoryServer改进 HSt ...

  6. “全能”选手—Django 1.10文档中文版Part2

    第一部分传送门 第三部分传送门 第四部分传送门 3.2 模型和数据库Models and databases 3.2.2 查询操作making queries 3.3.8 会话sessions 目录 ...

  7. Epplus

    简介:Epplus是一个使用Open Office XML(Xlsx)文件格式,能读写Excel 2007/2010文件的开源组件 功效:支持对excel文档的汇入汇出,图表(excel自带的图表基本 ...

  8. MVC 自定义Htmlhelper扩展

    在MVC中,我们不仅可以使用它原来的方法,我们还可以自定义,这不不仅加大了我们开发的效率,同时使界面更简洁. 具体什么是扩展方法,你可以这样理解,必须是静态且在形参中第一个参数是以this开头,大概先 ...

  9. 如何实现在PHP中调用JAVA

    详细说明:http://php.662p.com/thread-275-1-1.html PHP与JAVA JAVA是个非常强大的编程利器,它的扩展库也是非常的有用,这篇教程,主要讲述怎样使用PHP调 ...

  10. 【linux草鞋应用编程系列】_3_ 进程间通信

    一.进程间通信        linux下面提供了多种进程间通信的方法, 管道.信号.信号量.消息队列.共享内存.套接字等.下面我们分别 介绍管道.信号量.消息队列.共享内存.        信号和套 ...