Mysql优化之创建高性能索引(三)
聚蔟索引
聚蔟索引并不是一种单独的索引类型,而是一种数据存储方式。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优化之创建高性能索引(三)的更多相关文章
- Mysql优化之创建高性能索引(一)
1.索引基础 索引对于良好的性能非常关键.尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要.但是不恰当的索引随着数据量的增加,也会使整个数据库的性能下降. 举个例子: ; 如果在id上建立索引 ...
- Mysql优化之创建高性能索引(二)
1.索引的优点 索引可以让服务器快速地定位到表的指定位置.总结下来有三大优点: 索引大大减少了服务器需要扫描的数据量 索引可以帮助服务器避免排序和临时表 索引可以将随机I/O变为顺序I/O 2.高性能 ...
- php面试专题---16、MySQL创建高性能索引考点
php面试专题---16.MySQL创建高性能索引考点 一.总结 一句话总结: 注意:只写精品 1.索引的基础? 类似书籍的目录:索引类似于书籍的目录,要想找到一本书的某个特定主题,需要先查找书的目录 ...
- mysql笔记02 创建高性能的索引
创建高性能的索引 1. 索引(在MySQL中也叫做"键(key)")是存储引擎用于快速找到记录的一种数据结构. 2. 索引可以包含一个或多个列的值.如果索引包含多个列,那么列的顺序 ...
- MySQL 创建高性能索引
索引是存储引擎用于快速找到记录的一种数据结构.除了加速查找,索引在其他方面也有一些有用的属性.索引对于良好的性能非常关键.尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要.在数据量较小且负载较 ...
- MySQL创建高性能索引
参考<高性能MySQL>第3版 1 索引基础 1.1 索引作用 在MySQL中,查找数据时先在索引中找到对应的值,然后根据匹配的索引记录找到对应的数据行,假如要运行下面查询语句: 如果在u ...
- 《高性能MySQL》——第五章创建高性能索引
1.创建索引基本语法格 在MySQL中,在已经存在的表上,可以通过ALTER TABLE语句直接为表上的一个或几个字段创建索引.基本语法格式如下: ALTER TABLE 表名 ADD [UNIQUE ...
- PHP面试 MySQL创建高性能索引考点
MySQL索引 MySQL索引的基础和类型 索引的基础:索引类似于书籍的目录,要想找到一本书的某个特定篇章,需要查找书的目录,定位对应的页码 存储引擎使用类似的方式进行数据查询,先去索引当中找到对应的 ...
- [MySQL-笔记]创建高性能索引
索引,MySQL中也叫“键”,是存储引擎中用于快速找到记录的一种数据结构,具体的工作方式就像书本中的索引一样,但是具体的实现方式会有差别. 一.索引分类 B-Tree索引: 优点: MyISAM中,索 ...
随机推荐
- Comparator TreeSet
package study; import java.util.Comparator;import java.util.TreeSet; public class TreeSetTest { publ ...
- UVA 221 - Urban Elevations(离散化)!!!!!!
题意:给出一张俯视图.给出N个建筑物的左下标,长度,宽度,高度.现在求,从南面看,能看到那些建筑? Sample Input 14 160 0 30 60 30 125 0 32 28 60 95 0 ...
- C#解析JSON数据
本篇文章主要介绍C#对Json数据的读取. 主要操作过程是: 发送Http请求获取Json数据 把获取的Json数据转换成C#中的类 下面我们以12306火车票余票的数据为例进行切入. 首先来看一下h ...
- dede调用指定栏目的标签
{dede:type typeid='1'} <a href="[field:typelink /]">[field:typename /]</a> {/d ...
- Python模块的介绍
Python模块的学习: 1.os模块: 下面只对os模块中几个比较常用的方法做一些简单的示例: os.system():这个方法在shell中体现的比较多,在dos命令行中也可以执行,下面就以在do ...
- UPX和WinUpack压缩壳的使用和脱法 - 脱壳篇06
UPX和WinUpack压缩壳的使用和脱法 - 脱壳篇06 让编程改变世界 Change the world by program 今天小甲鱼给大家介绍两款压缩壳:UPX和WinUpack. UPX是 ...
- OC 代理 协议 委托 数据源的概念
(网摘) OBJC 中的 protocol 相当于 java 里的接口,delagate 就是接口的实现类(C中的回调类似 ): 数据源就是对象遵循了存储数据的协议,可以存储使用数据 协议表示了方法可 ...
- 运行时数据区即内存分配管理——JVM之六
内存分配结构,请参考: http://iamzhongyong.iteye.com/blog/1333100
- unzip解压中文文件名乱码
由于中文的Windows使用的是GBK编码,而Linux默认使用UTF-8编码的,如果在Windows打包带中文文件的zip包,则这个zip包在Linux下面使用默认的归档管理器打开这个zip包的时候 ...
- javacc
http://www.cnblogs.com/Gavin_Liu/archive/2009/03/07/1405029.html https://javacc.java.net/ http://www ...