聚簇索引与非聚簇索引(也叫二级索引)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聚簇索引与非聚簇索引(也叫二级索引)相关的知识,希望对你有一定的参考价值。

参考技术A

澄清一个概念:innodb中,在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是行的物理位置,而是主键值

由于聚簇索引是将数据跟索引结构放到一块,因此一个表仅有一个聚簇索引

聚簇索引默认是主键 ,如果表中没有定义主键,InnoDB 会选择一个 唯一的非空索引 代替。如果没有这样的索引,InnoDB 会 隐式定义一个主键 来作为聚簇索引。InnoDB 只聚集在同一个页面中的记录。包含相邻健值的页面可能相距甚远。 如果你已经设置了主键为聚簇索引,必须先删除主键,然后添加我们想要的聚簇索引,最后恢复设置主键即可

此时其他索引只能被定义为非聚簇索引。这个是最大的误区。有的主键还是无意义的自动增量字段,那样的话Clustered index对效率的帮助,完全被浪费了。

刚才说到了,聚簇索引性能最好而且具有唯一性,所以非常珍贵,必须慎重设置。 一般要根据这个表最常用的SQL查询方式来进行选择,某个字段作为聚簇索引,或组合聚簇索引 ,这个要看实际情况。

记住我们的 最终目的 就是 在相同结果集情况下,尽可能减少逻辑IO

MyISM使用的是非聚簇索引, 非聚簇索引的两棵B+树看上去没什么不同 ,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于 索引树是独立的,通过辅助键检索无需访问主键的索引树

看上去聚簇索引的效率明显要低于非聚簇索引,因为 每次使用辅助索引检索都要经过两次B+树查找 ,这不是多此一举吗?聚簇索引的优势在哪?

所以建议使用int的auto_increment作为主键

主键的值是顺序的,所以 InnoDB 把每一条记录都存储在上一条记录的后面。当达到页的最大填充因子时(InnoDB 默认的最大填充因子是页大小的 15/16,留出部分空间用于以后修改),下一条记录就会写入新的页中。一旦数据按照这种顺序的方式加载,主键页就会近似于被顺序的记录填满(二级索引页可能是不一样的)

聚簇索引的数据的物理存放顺序与索引顺序是一致的 ,即: 只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的 。如果主键不是自增id,那么可以想 象,它会干些什么,不断地调整数据的物理地址、分页,当然也有其他一些措施来减少这些操作,但却无法彻底避免。但,如果是自增的,那就简单了,它只需要一 页一页地写,索引结构相对紧凑,磁盘碎片少,效率也高。

因为 MyISAM的主索引并非聚簇索引,那么他的数据的物理地址必然是凌乱的,拿到这些物理地址,按照合适的算法进行I/O读取,于是开始不停的寻道不停的旋转 聚簇索引则只需一次I/O 。(强烈的对比)

不过,如果 涉及到大数据量的排序、全表扫描、count之类的操作的话,还是MyISAM占优势些,因为索引所占空间小,这些操作是需要在内存中完成的

聚簇索引 默认是主键 ,如果表中没有定义主键,InnoDB 会选择一个 唯一的非空索引 代替。如果没有这样的索引,InnoDB 会 隐式定义一个主键 来作为聚簇索引。 InnoDB 只聚集在同一个页面中的记录。包含相邻健值的页面可能相距甚远。

数据库中聚簇索引与非聚簇索引的区别 (整理)

一、定义:

  聚簇索引也叫簇类索引,是一种对磁盘上实际数据重新组织以按指定的一个或多个列的值排序。由于聚簇索引的索引页面指针指向数据页面,所以使用聚簇索引查找数据几乎总是比使用非聚簇索引快。每张表只能建一个聚簇索引,并且建聚簇索引需要至少相当该表120%的附加空间,以存放该表的副本和索引中间页。

  非聚簇索引,叶级页指向表中的记录,记录的物理顺序与逻辑顺序没有必然的联系。非聚簇索引则更像书的标准索引表,索引表中的顺序通常与实际的页码顺序是不一致的。

 

二、举例说明:

仅从定义来看非常抽象,下面就举例说明下两者之间的区别:
  以一本英文课本为例,要找第8课,直接翻书,若先翻到第5课,则往后翻,再翻到第10课,则又往前翻。这本书本身就是一个索引,即“聚簇索引”。
  如果要找"fire”这个单词,会翻到书后面的附录,这个附录是按字母排序的,找到F字母那一块,再找到"fire”,对应的会是它在第几课。这个附录,为“非聚簇索引”。
由此可见,聚簇索引,索引的顺序就是数据存放的顺序,所以,很容易理解,一张数据表只能有一个聚簇索引。聚簇索引要比非聚簇索引查询效率高很多,特别是范围查询的时候。

 

三、思想

  1、大多数表都应该有聚簇索引或使用分区来降低对表尾页的竞争,在一个高事务的环境中,对最后一页的封锁严重影响系统的吞吐量。
  2、在聚簇索引下,数据在物理上按顺序排在数据页上,重复值也排在一起,因而在那些包含范围检查(between、<、<=、>、>=)或使用group by或orderby的查询时,一旦找到具有范围中第一个键值的行,具有后续索引值的行保证物理上毗连在一起而不必进一步搜索,避免了大范围扫描,可以大大提高查询速度。
  3、在一个频繁发生插入操作的表上建立聚簇索引时,不要建在具有单调上升值的列(如IDENTITY)上,否则会经常引起封锁冲突。
  4、在聚簇索引中不要包含经常修改的列,因为码值修改后,数据行必须移动到新的位置。
  5、选择聚簇索引应基于where子句和连接操作的类型。

  每个表只能有一个聚簇索引,因为一个表中的记录只能以一种物理顺序存放。但是,一个表可以有不止一个非聚簇索引。实际上,对每个表你最多可以建立249个非聚簇索引。非聚簇索引需要大量的硬盘空间和内存。另外,虽然非聚簇索引可以提高从表中取数据的速度,它也会降低向表中插入和更新数据的速度。每当你改变了一个建立了非聚簇索引的表中的数据时,必须同时更新索引。因此你对一个表建立非聚簇索引时要慎重考虑。如果你预计一个表需要频繁地更新数据,那么不要对它建立太多非聚簇索引。另外,如果硬盘和内存空间有限,也应该限制使用非聚簇索引的数量

 

四、优化原则

  1、缺省情况下建立的索引是非聚簇索引,但有时它并不是最佳的。在非群集索引下,数据在物理上随机存放在数据页上。合理的索引设计要建立在对各种查询的分析和预测上。一般来说: 
    a.有大量重复值、且经常有范围查询( > ,< ,> =,< =)和order by、group by发生的列,可考 
   虑建立群集索引; 
    b.经常同时存取多列,且每列都含有重复值可考虑建立组合索引; 
    c.组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列。索引虽有助于提高性能但不是索引越多越好,恰好相反过多的索引会导致系统低效。用户在表中每加进一个索引,维护索引集合就要做相应的更            新工作。 
  2、ORDER BY和GROPU BY使用ORDER BY和GROUP BY短语,任何一种索引都有助于SELECT的性能提高。 
  3、多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方案并从中找出系统开销最小的最佳方案。连接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外层表中的匹配行数*内层表         中每一次查找的次数确定,乘积最小为最佳方案。
     4、任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
  5、IN、OR子句常会使用工作表,使索引失效。如果不产生大量重复值,可以考虑把子句拆开。拆开的子句中应该包含索引。

  SQLServer缺省情况下建立的索引是非聚簇索引,由于非聚簇索引不重新组织表中的数据,而是对每一行存储索引列值并用一个指针指向数据所在的页面。换句话说非聚簇索引具有在索引结构和数据本身之间的一个额外级。一个表如果没有聚簇索引时,可有250个非聚簇索引。每个非聚簇索引提供访问数据的不同排序顺序。在建立非聚簇索引时,要权衡索引对查询速度的加快与降低修改速度之间的利弊。另外,还要考虑这些问题:
  1、索引需要使用多少空间。
  2、合适的列是否稳定。
  3、索引键是如何选择的,扫描效果是否更佳。
  4、是否有许多重复值。
  对更新频繁的表来说,表上的非聚簇索引比聚簇索引和根本没有索引需要更多的额外开销。对移到新页的每一行而言,指向该数据的每个非聚簇索引的页级行也必须更新,有时可能还需要索引页的分理。从一个页面删除数据的进程也会有类似的开销,另外,删除进程还必须把数据移到页面上部,以保证数据的连续性。所以,建立非聚簇索引要非常慎重。非聚簇索引常被用在以下情况:
  1、某列常用于集合函数(如Sum,....)。
  2、某列常用于join,order by,group by。
  3、查寻出的数据不超过表中数据量的20%。

五、应用场景:

动作

使用聚簇索引

使用非聚簇索引

列经常被分组排序

       应

      应

返回某范围内的数据

       应

     不应

一个或极少不同值

      不应

     不应

小数目的不同值

       应

     不应

大数目的不同值

      不应

      应

频繁更新的列

      不应

      应

外键列

       应

      应

主键列

       应

      应

频繁修改索引列

      不应

      应

以上是关于聚簇索引与非聚簇索引(也叫二级索引)的主要内容,如果未能解决你的问题,请参考以下文章

聚簇索引与非聚簇索引

聚簇索引与非聚簇索引

聚簇索引与非聚簇索引的区别

Mysql优化聚簇索引与非聚簇索引概念

MySql聚簇索引与非聚簇索引的区别

聚簇索引与非聚簇索引的区别