

前期回顾:
一、索引失效
select id,name,age from t_user where age + 1 = 7;二、前缀索引和索引选择性
三、多列索引
三星索引:在Lahdenmaki和Leach编写的Relational Database Index Design and the Optimizers一书中,提到如何评价一个索引是否适合某个查询的“三星系统”:索引将相关的记录放到一起则获得“一星”;如果索引中的数据顺序和查找中的排序顺序一致则获得“二星”;如果索引中的列包含了查询中需要的全部列则获得“三星”。
mysql> show create table t_user;+--------+---------------+| Table | Create Table |+--------+---------------+| t_user | CREATE TABLE `t_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`age` int(11) DEFAULT NULL,KEY `idx` (`id`,`name`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 |+--------+-----------------------------------------+1 row in set
根据id进行查询,具体如下:
mysql> explain select * from t_user where id = 1;+----+-------------+--------+------------+------+---------------+-----+---------+-------+------+----------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+--------+------------+------+---------------+-----+---------+-------+------+----------+-------+| 1 | SIMPLE | t_user | NULL | ref | idx | idx | 4 | const | 1 | 100 | NULL |+----+-------------+--------+------------+------+---------------+-----+---------+-------+------+----------+-------+1 row in set
mysql> explain select * from t_user where name = 'xcbeyond';+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+| 1 | SIMPLE | t_user | NULL | ALL | NULL | NULL | NULL | NULL | 7 | 14.29 | Using where |+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+1 row in set
四、选择合适的索引列顺序
五、聚簇索引
InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。
非聚簇索引:将数据存储与索引分开存储,索引结构的叶子节点指向了数据的对应行。当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因。
InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,
InnoD会隐式定义一个主键来作为聚簇索引。
InnoDB只聚集在同一个页面中的记录,包括相邻键值的页面可能会相距甚远。
InnoDB改成其他引擎的时候(反过来也一样)。
可以把相关数据保存在一起。例如实现电子邮箱时,可以根据用户ID来聚集数据,这样子只需要从磁盘中读取少数的数据也技能获取某个用户的全部邮件。 数据访问更快。聚簇索引把索引和数据都放在同一个B-Tree中,因此从聚簇索引中获取数据比从非聚簇索引中要快。 使用覆盖索引扫描的查询可以直接使用页节点中的主键值。
最大限度的提高了I/O密集型应用的性能,但如果数据全部都放在内存中,则访问的顺序就没那么重要了,聚簇索引也就没什么优势了。 插入速度严重依赖于插入顺序。按照主键的顺序插入是加载数据到 InnoDB
表中速度最快的方式。但如果不是按照逐渐顺序加载数据,那么在加载完成后最好使用OPTIMIZE TABLE
重新组织一下表。更新聚簇索引列的代价很高。因为要强制InnoDB将每个被更新的行移动到新的位置。 基于聚簇索引的表在插入新行,或者主键被更新导致移动行的时候,可能面临“页分裂”的问题。当行的主键值要求必须将这一行插入到某个已满的页中时,存储引擎会将该页分裂成两个页来容纳该行,这就是一次页分裂操作,这也意味着这样导致表占用更多的磁盘空间。 聚簇索引可能导致全表扫描变慢,尤其是行比较稀疏时,或者由于页分裂导致数据存储不连续的时候。 二级索引(非聚簇索引)可能比想想的要更大。因为二级索引的叶子结点包含了引用行的主键列。 二级索引访问需要两次索引查找,而不是一次。
六、覆盖索引
索引条目通常远小于数据行的大小,所以如果只需要读取索引,那么MySQL就会极大的减少数据访问量。这对缓存的负载非常重要,因为这种情况下响应时间大部分花费在数据拷贝下。覆盖索引对于I/O密集型的应用也有帮助,因为索引比数据更小,更容易全部放进去内存。 因为索引是按照列值顺序存储的,对于I/O密集型的范围查询会比随机从磁盘读取每一行数据的I/O要少的多。对于某些存储引擎,例如 MyISAM
和Percona XtraDB
,甚至可以通过POTIMIZE
命令使得索引完全顺序排列,这样就可以让简单的范围查询能使用完全排序的索引访问。一些存储引擎,如 MyISAM
在内存中只缓存索引。数据则依赖于操作系统来缓存,因此要访问数据需要一次系统调用。这可能会导致严重的性能问题,尤其是那些系统调用占了数据访问中的最大开销的场景。由于 InnoDB
的聚簇索引,覆盖索引对于InnoDB表特别有用。InnoDB的二级索引在叶子节点保存了行的主键值,所以如果二级主键能够覆盖查询,则可以避免对主键索引的二次查询
七、使用索引扫描来排序
EXPLAIN出来的type列的值为
index,则说明MySQL使用了索引扫描来做排序。
只有当索引的列顺序和 order by
子句的顺序完全一致,并且所有列的排序方向都一样时,MySQL才能够使用索引来对结果做排序。如果查询需要关联多张表,则只有当 order by
子句引用的字段全部为第一个表时,才能使用索引做排序。order by
子句和查找性查询的限制是一样的:需要满足索引的最左前缀的要求;否则,MySQL都需要执行的顺序操作,而无法使用索引排序。
八、冗余、重复索引
create table test{id int not null primary key,a int not null,b int not null,unique(id)index(id)}engine=InnoDB;
unique(id)),然后再加上索引(
index(id))以供查询使用。然而唯一限制和主键限制都是通过索引使用,因此,上面的写法实际上在相同的列上创建了三个重复的索引。通常并没有理由要这样做,除非是在同一列上创建不同类型的索引来满足不同的查询需求。
(A,B),再创建
(A)那就是冗余索引,因为A就是前一个索引的前缀索引。索引
(A,B)完全就可以当做A来使用。但是如果创建了索引
(B,A)那就不是冗余索引了,索引B也不是。因为B不是索引
(A,B)的最左前缀索引。另外,其他不同类型的索引,例如哈希,全文索引也不会是B-Tree的冗余索引。
(A,B)而不是拓展已有的索引
(A),还有一种情况是将一个索引扩展为
(A,ID),其中的ID是主键,对于
InnoDB来说主键列已经包含在二级索引当中了, 所以这也是冗余的。
varchar列,那性能可能会急剧下降。特别是有索引把这个索引当中覆盖索引时,或者这是
MyISAM表并且有很多范围查询的时候。
information_schema表的查询来找,不过还有两个更简单的方法就是使用
Shlomi Noach的
common_schema中的一些视图来定位(
common_schema是一系列可以安装在服务器上的常用的存储和视图)。另外一个方法就是使用
Percona Toolkit中的
pt_duplicate-key-checker,该工具通过分析表结构来找出冗余和重复索引。
九、未使用的索引
Performance_schema中的
table_io_waits_summary_by_index_usage表进行查找:
SELECT object_schema, object_name, index_name FROM performance_schema.table_io_waits_summary_by_index_usage WHERE index_name IS NOT NULL AND count_star = 0 ORDER BY object_schema, object_name, index_name;
十、索引和锁
InnoDB的行锁效率很高,内存使用也很少,但是锁定行的时候仍然会带来额外的开销,其次,锁定超过需要的行会增加锁争用并减少并发性。
十一、总结
在区分度高的字段上面建立索引可以有效的使用索引,区分度太低,无法有效的利用索引,可能需要扫描所有数据页,此时和不使用索引区别不大。 联合索引,注意最左匹配原则:必须按照从左到右的顺序匹配,MySQL会一直向右匹配直到遇到范围查询 (>、<、between、like)
就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4
如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。查询记录的时候,少使用*,尽量去利用索引覆盖,可以减少回表操作,提升效率。 有些查询可以采用联合索引,进而使用到索引下推,也可以减少回表操作,提升效率。 禁止对索引字段使用函数、运算符操作,这样将会使索引失效。 字符串字段和数字比较的时候会使索引无效。 模糊查询 '%值%'
会使索引无效,变为全表扫描,但是'值%'
这种可以有效利用索引。排序中尽量使用到索引字段,这样可以减少排序,提升查询效率。

MySQL性能优化(一):MySQL架构与核心问题 MySQL性能优化(二):选择优化的数据类型 MySQL性能优化(三):深入理解索引的这点事 微服务架构下的核心话题 (一):微服务架构下各类项目的顺势崛起 微服务架构下的核心话题 (二):微服务架构的设计原则和核心话题 微服务架构下的核心话题 (三):微服务架构的技术选型

喜欢就点个"在看"呗,留言、转发朋友圈
文章转载自程序猿技术大咖,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




