MySQL优化 - 索引优化
索引(在MySQL中也叫做“键(key)”)是存储引擎用于快速找到记录的一种数据结构。
索引对于良好的性能非常关键,尤其是当表的数据量越来越大时,索引对性能(查询)的影响愈发重要。
- 索引的类型
- 相关的说明请参考之前写的一篇文章:MySQL索引 - 索引的类型。
- 索引的优点(大致分为以下三点)
- 索引大大减少了服务器需要扫描的数据量。
- 索引可以帮助服务器避免排序和临时表。
- 索引可以将随机I/O变为顺序I/O。
- 如何创建高性能的索引
- 索引列不能是表达式的一部分,也不能是函数的参数,如下是不恰当的写法:
mysql> SELECT * FROM TB1 WHERE num + 1 = 5;
mysql> SELECT * FROM TB1 WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(ctime) < 10;
- 在多个列上建立独立的单列索引大部分情况下并不能提高MySQL的查询性能,如下是不恰当的写法:
mysql> CREATE TABLE TB4(
-> c1 INT,
-> c2 INT,
-> c3 INT,
-> key(c1),
-> key(c2),
-> key(c3));mysql> EXPLAIN SELECT * FROM TB4 WHERE c1=1 OR c2=1 OR c3=1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB4
partitions: NULL
type: ALL
possible_keys: c1,c2,c3
key: NULL
key_len: NULL
ref: NULL
rows: 6
filtered: 42.13
Extra: Using where - 当不需要考虑排序和分组时,将选择性最高的列放在最左边通常是最好的,可以使用以下方法来查看基数和选择性(这里对比TB1表中的name和num字段):
mysql> SELECT COUNT(DISTINCT name)/COUNT(*) AS name_selectivity,
-> COUNT(DISTINCT num)/COUNT(*) AS num_selectivity,
-> COUNT(*)
-> FROM TB1\G
*************************** 1. row ***************************
name_selectivity: 0.3479
num_selectivity: 0.0000
COUNT(*): 1750001可以看出name字段的选择性更高,所以将其作为索引列的第一列
mysql> ALTER TABLE TB1 ADD KEY(name, num);
- 使用覆盖索引(查询列要被所建的索引覆盖)。索引条目通常远小于数据行大小,所以如果只需要读取索引,可以极大地减少数据访问量,如下(TB1表中有一个多列索引name和num):
mysql> EXPLAIN SELECT name,num FROM TB1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: ref
possible_keys: IDX
key: IDX
key_len: 66
ref: const,const
rows: 15
filtered: 100.00
Extra: Using index上面的语句会使用到覆盖索引,Extra列可以看到Using index的信息。下面的例子没有任何索引能够覆盖这个查询,有两个原因,一是查询从表中选择了 所有列(*),二是MySQL不能再索引中执行LIKE操作:
mysql> EXPLAIN SELECT * FROM TB1 WHERE name='test1' AND nk LIKE '%a%'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: ref
possible_keys: IDX
key: IDX
key_len: 66
ref: const,const
rows: 15
filtered: 100.00
Extra: Using index condition # 在MySQL的5.6以下版本会显示Using index where我们可以通过重写查询设计索引来解决上面的查询语句,先将索引拓展至覆盖三个数据列(id,name,nk),然后按照如下方式重写查询(延迟关联):
mysql> EXPLAIN SELECT TB1.* FROM TB1 JOIN
-> (
-> SELECT id FROM TB1 WHERE name='test1' AND nk LIKE '%a%'
-> ) AS t1 ON
-> t1.id = TB1.id\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: ref
possible_keys: PRIMARY,IDX,IDX1
key: IDX
key_len: 62
ref: const
rows: 15
filtered: 11.11
Extra: Using where; Using index还有一种情况,在name字段有二级索引(除了聚簇索引,如果表上有主键,该主键索引就是聚簇索引。如果未定义主键,则取第一个唯一索引而且只含非空列作为主键,并使用它作为聚簇索引。如果没有这样的列,InnoDB就自己产生一个这样的ID值,它有六个字节,而且是隐藏的,使其作为聚簇索引,其他索引都为二级索引),虽然该索引列不包括主键id列,但也能够对id列进行覆盖查询,如下:
mysql> EXPLAIN SELECT id,name FROM TB1 WHERE name='test2'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: ref
possible_keys: IDX,IDX1
key: IDX
key_len: 62
ref: const
rows: 15
filtered: 100.00
Extra: Using index - 使用索引对结果做排序(当索引的列顺序和ORDER BY子句的顺序一致,并且所有列的排序方向(倒序或顺序)都一样时,可以使用索引对结果做排序),如下(假设TB1表中有一个多列索引(num,name,nk)):
mysql> EXPLAIN SELECT * FROM TB1 WHERE num='1' ORDER BY name, nk\G # 即使ORDER BY子句不满足作引的最左前缀要求,也可用于查询排序,因为索引的第一列(num)被指定为一个常数
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: ref
possible_keys: IDX2
key: IDX2
key_len: 4
ref: const
rows: 872985
filtered: 100.00
Extra: Using index conditionmysql> EXPLAIN SELECT * FROM TB1 WHERE num>'1' ORDER BY num, name\G # 这个查询也没问题,ORDER BY使用的两列就是索引的最左前缀
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: range
possible_keys: IDX2
key: IDX2
key_len: 4
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition下面是一些反例:
mysql> EXPLAIN SELECT * FROM TB1 WHERE num>'1' ORDER BY name, nk\G # 这个查询是错误的,索引的第一列(num)被指定为一个范围,且ORDER BY不满足最左前缀
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: range
possible_keys: IDX2
key: IDX2
key_len: 4
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition; Using filesortmysql> EXPLAIN SELECT * FROM TB1 WHERE num='1' ORDER BY name DESC, nk ASC\G # 这个查询使用了两种不同的排序方向,但索引是顺序排序的
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: ref
possible_keys: IDX2
key: IDX2
key_len: 4
ref: const
rows: 872985
filtered: 100.00
Extra: Using index condition; Using filesortmysql> EXPLAIN SELECT * FROM TB1 WHERE num='1' ORDER BY name, ctime\G # 这个查询的ORDER BY 引用了一个不再索引的中列(ctime)
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: ref
possible_keys: IDX2
key: IDX2
key_len: 4
ref: const
rows: 872985
filtered: 100.00
Extra: Using index condition; Using filesortmysql> EXPLAIN SELECT * FROM TB1 WHERE num='1' ORDER BY nk\G # 这个查询的WHERE 和ORDER BY 中的列无法组合成索引的最左前缀
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: ref
possible_keys: IDX2
key: IDX2
key_len: 4
ref: const
rows: 872985
filtered: 100.00
Extra: Using index condition; Using filesortmysql> EXPLAIN SELECT * FROM TB1 WHERE num='1' AND name IN('test1','test2') ORDER BY nk\G # 这个查询在name列上有多个等于条件,对于排序来说,也是范围查询
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB1
partitions: NULL
type: range
possible_keys: IDX2
key: IDX2
key_len: 66
ref: NULL
rows: 30
filtered: 100.00
Extra: Using index condition; Using filesort - MyISAM使用前缀压缩来减少索引的大小,从而让更多的索引可以放入内存中,在某些情况能极大的提高性能。MyISAM压缩每个索引块的方法是:先保存索引块中的一个值,然后将其他值和第一个值进行比较得到相同前缀的字节数和剩余的不同后缀部分,把这部分存储起来即可。例如,索引块中的第一个值是“test”,第二个值是“test88888”,那么第二个值的前缀压缩后存储的是类似“4,88888”这样的形式。压缩块使用更少空间,但代价是某些操作可能更慢。因为每个值的压缩前缀都依赖前面的值,所以MyISAM查找时无法在索引块使用二分查找而只能从头开始扫描,顺序的扫描速度不错,但如果是倒序扫描(DESC)就不是很好了,所以在块中查找某一行的操作平均都需要扫描半个索引块。
- 避免重复索引(在相同的列上按照相同的顺序创建的相同类型的索引),如下:
mysql> CREATE TABLE TB5(
-> ID INT NOT NULL PRIMARY KEY,
-> A INT NOT NULL,
-> B INT NOT NULL,
-> UNIQUE(ID),
-> INDEX(ID)
-> ) ENGINE=InnoDB;PS:MySQL的唯一限制和主键限制都是通过索引实现的,因此上面的写法实际上在相同的列上创建了三个重复的索引。通常没有理由这样做,除非是在同一列上创建不同类型的索引来满足不同的查询需求。
- 避免冗余索引(创建了索引(A,B),在创建索引(A)就是冗余索引),如下:
mysql> CREATE TABLE TB6(
-> A INT NOT NULL,
-> B INT NOT NULL,
-> INDEX IDX(A,B),
-> INDEX IDX1(A)
-> ) ENGINE=InnoDB;PS:对于B-Tree索引来说,索引(A,B)也可以当作索引(A)来使用,但如果在创建索引(B,A)则不是冗余索引。
- 索引列不能是表达式的一部分,也不能是函数的参数,如下是不恰当的写法:
MySQL优化 - 索引优化的更多相关文章
- 知识点:Mysql 数据库索引优化实战(4)
知识点:Mysql 索引原理完全手册(1) 知识点:Mysql 索引原理完全手册(2) 知识点:Mysql 索引优化实战(3) 知识点:Mysql 数据库索引优化实战(4) 一:插入订单 业务逻辑:插 ...
- mysql使用索引优化查询效率
索引的概念 索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针.更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度.在没 ...
- mysql数据库索引优化与实践(一)
前言 mysql数据库是现在应用最广泛的数据库系统.与数据库打交道是每个Java程序员日常工作之一,索引优化是必备的技能之一. 为什么要了解索引 真实案例 案例一:大学有段时间学习爬虫,爬取了知乎30 ...
- 【mysql】索引优化记录
基础知识 Innodb存储引擎 支持行锁 支持事务: Myisam存储引擎 只支持表锁: 不支持事务: 常见索引列表 独立的列 前缀索引(索引选择性) 多列索引(并不是多个单列索引,索引顺序很重要) ...
- MySQL高级-索引优化
索引失效 1. 2.最佳左前缀法则 4. 8. 使用覆盖索引解决这个问题. 二.索引优化 1.ORDER BY 子句,尽量使用Index方式排序,避免使用FileSort方式排序 MySQL支持两种方 ...
- MySQL的索引优化,查询优化
MySQL逻辑架构 如果能在头脑中构建一幅MySQL各组件之间如何协同工作的架构图,有助于深入理解MySQL服务器.下图展示了MySQL的逻辑架构图. MySQL逻辑架构,来自:高性能MySQL My ...
- mysql数据库索引优化
参考 :http://www.cnblogs.com/yangmei123/archive/2016/04/10/5375723.html MySQL数据库的优化: 数据库优化的目的: ...
- MySQL的索引优化分析(一)
一.SQL分析 性能下降.SQL慢.执行时间长.等待时间长 查询语句写的差 索引失效关联查询太多join(设计缺陷) 单值索引:在user表中给name属性创建索引,create index idx_ ...
- MySQL的索引优化分析(二)
一.索引优化 1,单表索引优化 建表 CREATE TABLE IF NOT EXISTS article( id INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO ...
- mysql前缀索引优化示例
现有一数据表,数据量79W, 微信openid字段为定长28位char型,目前是做的全字段索引,需要做一下索引优化,. 我们先来看下选择性, 全字段索引的: SELECT COUNT(DISTINCT ...
随机推荐
- django2.0+linux服务器 ,如何让自己电脑访问
这几天一直在搞这个服务器端口开放问题,来让自己电脑可以访问服务器下的django网页,今天终于弄好了~~~~~离成功又进了一步~~~~~ 1.首先,我们来开放一个linux服务器的端口(我开放了828 ...
- 监听键盘弹起View上调
可以用三方库IQKeyboardManager 用这个第三方 http://www.jianshu.com/p/f8157895 #pragma mark - keyboard events - // ...
- iOS 网络状态判断方案(支持iOS11和iPhoneX)
在之前的iPhone中.我们可以根据导航栏上方的网络状态view.来判断网络状态.(这种方案本来就不太好) 这种方案在iPhone X 手机上.不可使用. 我们可以通过 Reachability 来 ...
- 动态WebApi
动态WebApi实现了直接对Service的调用,其实没有跨过ApiController,只是我们自己创建出ApiController 实现主要分以下几步 一 对默认WebApi服务的替换 ApiGl ...
- ABP-Module
[TOC] 什么是Module? Module就是模块化的设计思想.开发人员可以将自定义的功能以模块的形式集成到项目中.具体的功能也可以设计成一个单独的模块 AbpModule AbpModule是所 ...
- 消息服务框架(MSF)应用实例之分布式事务三阶段提交协议的实现
一,分布式事务简介 在当前互联网,大数据和人工智能的热潮中,传统企业也受到这一潮流的冲击,纷纷响应国家“互联网+”的战略号召,企业开始将越来越多的应用从公司内网迁移到云端和移动端,或者将之前孤立的IT ...
- 学习ABP ASP.NET Core with Angular 环境问题
1. 前言 最近学习ABP架构 搭建ASP.NET Core with Angular遇到了些问题,折腾了一个礼拜最终在今天解决了,想想这个过程的痛苦就想利用博客记录下来.其实一直想写博客,但因为 时 ...
- 探索C++对象模型
只说C++对象模型在内存中如何分配这是不现实的,所以这里选择VS 2013作为调试环境具体探讨object在内存中分配情况.目录给出了具体要探讨的所有模型,正文分标题依次讨论.水平有限,如有错误之处请 ...
- 【Zookeeper】源码分析之服务器(五)之ObserverZooKeeperServer
一.前言 前面分析了FollowerZooKeeperServer,接着分析ObserverZooKeeperServer. 二.ObserverZooKeeperServer源码分析 2.1 类的继 ...
- 虚拟机创建流程中neutron代码分析(三)
前言: 当neutron-server创建了port信息,将port信息写入数据库中.流程返回到nova服务端,接着nova创建的流程继续走.在计算节点中neutron-agent同样要完成很多的工作 ...