前言: 本文对这篇博客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. php使用递归创建多级目录

    <?php header('Content-type:text/html;charset=utf8'); echo "Loading time:".date('Y-m-d H ...

  2. struts2学习笔记--struts.xml配置文件详解

    这一节主要讲解struts2里面的struts.xml的常用标签及作用: 解决乱码问题 <constant name="struts.i18n.encoding" value ...

  3. 【JUC】JDK1.8源码分析之CopyOnWriteArrayList(六)

    一.前言 由于Deque与Queue有很大的相似性,Deque为双端队列,队列头部和尾部都可以进行入队列和出队列的操作,所以不再介绍Deque,感兴趣的读者可以自行阅读源码,相信偶了Queue源码的分 ...

  4. iis7.0上发布mvc4.0网站

    步骤如下: 1.右击需要发布的项目,在弹出的菜单中选择“发布...”选项 2.在“发布web”对话框中进行设置,配置文件名称默认为“配置文件1”可以修改为需要的名字,以便识别,也可以不改.发布方法选择 ...

  5. Winform应用程序实现通用消息窗口

    记得我之前发表过一篇文章<Winform应用程序实现通用遮罩层>,是实现了透明遮罩的消息窗口,功能侧重点在动图显示+消息提醒,效果看上去比较的炫,而本篇我又来重新设计通用消息窗口,功能重点 ...

  6. WPF数据编辑的提交与撤销

    当为一个集合(通常绑定在DataGrid或其它ItemsControl控件)添加或编辑一个项时,通常会弹出一个编辑界面编辑项的属性,编辑结束再提交,或者我们不想编辑数据了,此时选择取消,数据项的内容没 ...

  7. codeforces 632+ E. Thief in a Shop

    E. Thief in a Shop time limit per test 5 seconds memory limit per test 512 megabytes input standard ...

  8. Java02

    一.IDE的概念.eclipse的介绍.安装.使用 (用eclipse写HelloWorld例子)     1.什么是IDE(Integrated Development Environment)? ...

  9. [连载]《C#通讯(串口和网络)框架的设计与实现》- 5.串口和网络统一IO设计

    目       录 第五章           串口和网络统一IO设计... 2 5.1           统一IO接口... 2 5.1.1    串口IO.. 4 5.1.2    网络IO.. ...

  10. 使用CSS把ul,li制作成表格

    查看效果:http://hovertree.com/texiao/css/7.htm 具体实现请看样式部分. 完整代码: <!DOCTYPE html> <html> < ...