聚蔟索引

聚蔟索引并不是一种单独的索引类型,而是一种数据存储方式。Innodb的聚蔟索引在同一结构保存了B-Tree索引和数据行。

当表有聚蔟索引时,它的数据行实际上存放在索引的叶子页中。下图展示了聚蔟索引中的记录是如何存放的。注意到,叶子页包含了行的全部数据,但是节点页只包含了索引列。

聚集的数据有一些重要的优点:

  • 可以把相关的数据保存在一起。减少查找到ID后回行产生多一次的I/O
  • 数据访问更快。聚蔟索引把数据页和索引保存在同一个B-Tree结构,比非聚蔟索引在查找数据时少一次回表查询
  • 使用覆盖索引扫描的查询可以直接使用页节点中的主键值

当然,聚蔟索引也有一些缺点:

  • 如果数据放在内存中,聚蔟索引就没什么优势
  • 插入速度严重依赖于插入顺序。如果不是按主键顺序加载数据,那么加载完后最好使用OPTIMIZE TABLE 命令重新组织一下表。
  • 更新聚蔟索引列的代价很高,因为更新的行需要移动到新的位置
  • 基于聚蔟索引的表在插入新行或者主键被更新需要移动行时,会产生页分裂的问题。页分裂会导致表占用更多的磁盘空间。
  • 聚蔟索引可能会使全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致数据存储不连续的时候
  • 二级索引(非聚蔟索引)可能比想象的要更大,因为在二级索引的叶子节点包含了引用行的主键列。
  • 二级索引访问需要两次索引查找,而不是一次。

InnoDB和MyISAM的数据分布对比

聚蔟索引和非聚蔟索引的数据分布有区别,以及对于的主键索引和二级索引的数据分别以也有区别。来看看InnoDB和MyISAM是如何存储下面这个表的:

CREATE TABLE layout_test(
col1 int NOT NULL,
col2 int NOT NULL,
PRIMARY KEY(col1),
KEY(col2)
);

假设该表的主键取值1--100001,随机插入并使用OPTIMIZE TABLE 命令做优化。也就是说,数据在磁盘的存储方式已经最优,但行的顺序是随机的。列col2的值是从1--100之间随机赋值,所以有很多重复的值。

MyISAM的数据分布比较简单,如下图:

在行的旁边显示了行号,从0递增,所以MyISAM可以从表的开头跳过所需的字节找到所需的行。这种分布方式很容易创建索引。下面显示的一系列图,因此了页的物理细节,只显示索引中的“节点”,索引中的每个叶子节点包含行号。图一为主键分布,图二为col2索引列分布

InnoDB的数据分布。因为InnoDB支持聚蔟索引,所以用不同的方式存储同样的数据。下图为InnoDB表的主键分布。

聚蔟索引的每一个叶子节点都包含了主键值,事务ID,用于事务和MVCC(多版本控制)的回滚指针以及所有的剩余列。

还有一点与MyISAM不同的是,InnoDB的二级索引和聚蔟索引很不相同。

这样做的好处是减少了当出现行移动或者数据页分裂时二级索引的维护工作。使用主键值当作指针会让二级索引占用更多的空间,换来的好处是,InnoDB在移动行是无需更新二级索引中的这个“指针”。

下图是描述InnoDB和MyISAM如何存放表的抽象图。

在InnoDB表中按主键顺序插入行

最好避免随机的聚蔟索引,特别是I/O密集型的应用。例如,从性能的角度考虑,使用UUID来作为聚蔟索引则会很糟糕,它使得聚蔟索引的插入变得完成随机。

为了演示这一点,我们做如下两个基准测试。第一个使用整数ID插入userinfo表:

CREATE TABLE userinfo
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name varchar() NOT NULL DEFAULT '',
email varchar() NOT NULL DEFAULT '',
password varchar() NOT NULL DEFAULT '',
dob date DEFAULT NULL,
address varchar() NOT NULL DEFAULT '',
city varchar() NOT NULL DEFAULT '',
state_id tinyint unsigned NOT NULL DEFAULT '',
zip varchar() NOT NULL DEFAULT '',
country_id smallint unsigned NOT NULL DEFAULT '',
gender enum('M','F') NOT NULL DEFAULT 'M',
account_type varchar() NOT NULL DEFAULT '',
verified tinyint NOT NULL DEFAULT '',
allow_mall tinyint unsigned NOT NULL DEFAULT '',
parrent_account int unsigned NOT NULL DEFAULT '',
closest_airport varchar() NOT NULL DEFAULT '',
PRIMARY KEY(uuid),
UNIQUE KEY email (email),
KEY country_id (country_id),
KEY state_id (state_id),
KEY state_id_2 (state_id,city,address)
)ENGINE=InnoDB;

第二个例子是userinfo_uuid表,除了主键改为uuid varchar(32),其余和前面的userinfo表完全相同。

我们测试这两个表,先各自向表中插入100万条数据,然后再插入300万条数据。

userinfo插入100万条的时间 (插入时间随测试机的性能而异,大家看时间差距就好)

userinfo_uuid插入100万条的时间

userinfo插入300万条的时间

userinfo_uuid插入300万条的时间

向UUID主键插入行不仅花费时间长,而且索引占用空间更大。这一方面由于主键字段更长,另一方面毫无疑问是由于页分裂和碎片导致。

明白了原因,我们来看看第一个表插入数据时,索引发生了什么变化。下图显示了插满一个页面后继续插入相邻的下一个页面的场景。

再来看看第二个UUID表的插入有什么不同

可以看到,在插入UUID表中,移动行的情况非常频繁,这样会增加很多额外的工作,并导致数据分布不够优化。下面是总结的一些缺点:

  • 写入的目标页可能已经刷到磁盘并从缓存中删除,或者是还没有加载到缓存中,InnoDB在插入之前不得不先从磁盘读取目标页到内存中,这样会导致大量随机I/O。
  • 因为写入是乱序的,页分裂频繁。
  • 由于频繁的页分裂,页会变得稀疏并被不规则填充,最终导致数据有碎片。

在把这些随机值载入到聚蔟索引后,也许需要做一次OPTIMIZE TABLE 来重建表并优化页的填充。

从这个案例可以看到,使用InnoDB时应尽可能按主键顺序插入数据,并且尽可能地使用单调递增的聚蔟键的值来插入新行。

Mysql优化之创建高性能索引(三)的更多相关文章

  1. Mysql优化之创建高性能索引(一)

    1.索引基础 索引对于良好的性能非常关键.尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要.但是不恰当的索引随着数据量的增加,也会使整个数据库的性能下降. 举个例子: ; 如果在id上建立索引 ...

  2. Mysql优化之创建高性能索引(二)

    1.索引的优点 索引可以让服务器快速地定位到表的指定位置.总结下来有三大优点: 索引大大减少了服务器需要扫描的数据量 索引可以帮助服务器避免排序和临时表 索引可以将随机I/O变为顺序I/O 2.高性能 ...

  3. php面试专题---16、MySQL创建高性能索引考点

    php面试专题---16.MySQL创建高性能索引考点 一.总结 一句话总结: 注意:只写精品 1.索引的基础? 类似书籍的目录:索引类似于书籍的目录,要想找到一本书的某个特定主题,需要先查找书的目录 ...

  4. mysql笔记02 创建高性能的索引

    创建高性能的索引 1. 索引(在MySQL中也叫做"键(key)")是存储引擎用于快速找到记录的一种数据结构. 2. 索引可以包含一个或多个列的值.如果索引包含多个列,那么列的顺序 ...

  5. MySQL 创建高性能索引

    索引是存储引擎用于快速找到记录的一种数据结构.除了加速查找,索引在其他方面也有一些有用的属性.索引对于良好的性能非常关键.尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要.在数据量较小且负载较 ...

  6. MySQL创建高性能索引

    参考<高性能MySQL>第3版 1 索引基础 1.1 索引作用 在MySQL中,查找数据时先在索引中找到对应的值,然后根据匹配的索引记录找到对应的数据行,假如要运行下面查询语句: 如果在u ...

  7. 《高性能MySQL》——第五章创建高性能索引

    1.创建索引基本语法格 在MySQL中,在已经存在的表上,可以通过ALTER TABLE语句直接为表上的一个或几个字段创建索引.基本语法格式如下: ALTER TABLE 表名 ADD [UNIQUE ...

  8. PHP面试 MySQL创建高性能索引考点

    MySQL索引 MySQL索引的基础和类型 索引的基础:索引类似于书籍的目录,要想找到一本书的某个特定篇章,需要查找书的目录,定位对应的页码 存储引擎使用类似的方式进行数据查询,先去索引当中找到对应的 ...

  9. [MySQL-笔记]创建高性能索引

    索引,MySQL中也叫“键”,是存储引擎中用于快速找到记录的一种数据结构,具体的工作方式就像书本中的索引一样,但是具体的实现方式会有差别. 一.索引分类 B-Tree索引: 优点: MyISAM中,索 ...

随机推荐

  1. C++服务器设计(五):多设备类型及消息事件管理

    在传统的服务器系统中,服务器仅针对接收到的客户端消息进行解析,并处理后回复响应.在该过程中服务器并不会主动判断客户端类型.但在现实中,往往存在多种类型的客户端设备,比如物联网下的智能家居系统,就存在智 ...

  2. 安装ubuntu14.10系统的那些瞎折腾

    前段时间自作孽,安装了ubuntu14.04的64位系统,而我的笔记本又是那种老古董,2G的内存所以装好之后各种不稳定,索性这个周末就重装一下吧,本来打算是直接装我以前的那个ubuntu12.04-i ...

  3. 写入和读取LOB类型的对象

    ====写入数据============ create or replace procedure addWaterFallis directions clob; amount binary_integ ...

  4. transient 做个标记

    import java.io.*; import java.util.*; public class Logon implements Serializable { /** * */ private ...

  5. zend framework 初识

    1. 请求顺序 : index.php --> Bootstrap.php --> IndexController.php 2. 验证顺序 : Bootstrap.php function ...

  6. php error_log 详解

    定义和用法 error_log() 函数向服务器错误记录.文件或远程目标发送一个错误. 成功,返回 true,否则返回 false. error_log(error,type,destination, ...

  7. Python学习(六) Python数据类型:字典(重要)

    字典dict: 字典其实就相当于java里面的Map,用来存储键值对的.其中存储的数据时无序的. 假如有这样的数据: t1=['name','age','sex'] t2=['tom',30,'mal ...

  8. 使用Genymotion调试出现错误INSTALL_FAILED_CPU_ABI_INCOMPATIBLE解决办法【转自wjr2012的csdn blog】

    点击下载Genymotion-ARM-Translation.zip 将你的虚拟器运行起来,将下载好的zip包用鼠标拖到虚拟机窗口中,出现确认对跨框点OK就行.然后重启你的虚拟机.

  9. 工作中小知识点汇总(sql)

    1.with(nolock) 在查询表的时候加上它可以增加33%查询效率 例子:SELECT TOP 5 b.UserName,f.issuedDate,r.tktedTime,r.refundSig ...

  10. QTableView使用HTML显示富文本

    对于QTableView中的显示,我们前面介绍过很多种,其中包括:文本.进度条.复选框等,今天我们介绍一下关于富文本的显示. 可能绝大多数小伙伴会通过QAbstractTableModel中的data ...