前言: 本文对这篇博客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. 关于近段时间论坛型APP 的一段舍弃

    一直以为缓存务必要做的很好,好到什么程度呢,我曾这样想,用户在下滑数刷新的时候也要做到,先加载久缓存再加载新的,同时只改变旧的某些项.这样的想法真的很好!好到我花费了三天去设计数据库和服务器的 php ...

  2. (十三)WebGIS中工具栏的设计之命令模式

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 从这一章节开始我们将正式进入WebGIS的工具栏中相关功能的 ...

  3. Android 源码下载方法(Git 方式clone)

    Android源码对于Android开发者来说,迟早有一天你会用到的,所以就记录一下,分享给读者,希望对读者有用 这里需要使用到Git相关知识,不清楚的可以先阅读,了解的可以跳过 Git-Tortoi ...

  4. using语法糖详解 2015-01-06 17:45 50人阅读 评论(0) 收藏

    前段事件在using外套try catch 突然想到,如果出现异常 会不会执行释放,不执行的话那服务器很可能导致崩溃... 特意上了CSDN问了大神..得到了答案.. Using相等于try catc ...

  5. C#中 @ 的3种用途

    1.忽略转义字符例如string fileName = "D:\\文本文件\\text.txt";使用@后string fileName = @"D:\文本文件\text ...

  6. Visual Studio 2013 Unit Test Project App.config文件设置方法

    开放中经常会要做单元测试,新的项目又没有单元测试项目,怎么才能搭建一个单元测试项目呢? 下面跟我四步走,如有错误之处,还请指正! 1.添加项目 2.添加配置文件 新建app.config文件,注意不是 ...

  7. SignalR入门篇

    写在前面的废话 在写关于SignalR的学习笔记之前研究了几天的webSocket,毕竟这才是未来的技术趋势,虽然很早就听说过WebSocket,但是并没有在实际项目中遇到过,所以也就没有深入研究.通 ...

  8. jQuery省市区三级联动插件

    体验效果:http://hovertree.com/texiao/bootstrap/4/支持PC和手机移动端. 手机扫描二维码体验效果: 代码如下: <!DOCTYPE html> &l ...

  9. PHP 检测机器人,屏蔽内页

    PHP 检测机器人,屏蔽内页 <?php // SpiderHelper::rewrite301(); // SpiderHelper::showRobotTxt(); class Spider ...

  10. JVM-String比较-字节码分析

    一道String字符串比较问题引发的字节码分析 public class a { public static void main(String[] args)throws Exception{ } p ...