MySQL之索引,执行计划及SQL优化
1.1 索引的分类
- 从功能逻辑上说,分为普通索引,唯一索引,主键索引,全文索引
- 从物理实现方式上说,分为聚簇索引,非聚簇索引(2级索引)
- 从字段个数上来说,分为分为单列索引,联合索引
1.2 适合创建索引的情况
- 字段的数值有唯一性的限制
- 频繁作为where查询条件的字段
- 经常group by 和order by的列
- update,delete的where列
- distinct字段需要创建索引
- 使用列的类型小的创建索引
- 使用字符串前缀创建索引(在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。)
- 使用最频繁的列放到联合索引的左侧(最左前缀原则)
- 在多个字段都要创建索引的情况下,联合索引优于单值索引
1.3 不适合创建索引的情况
- 在where中使用不到的字段,不要建索引
- 数据量小的表不要建索引
- 有大量重复数据的列上不要建索引
- 避免对经常更新的表创建索引
- 不建议用无序的值作为索引
- 删除不再使用或很少使用的索引
- 不定义冗余或重复的索引
1.4 索引失效的情况
(1)最佳左前缀原则(索引文件具有B-Tree的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引)
eg:CREATE INDEX idx_age_name_classId ON student(age,name,classId);
EXPLAIN SELECT * FROM student WHERE name='DzQJIv' and classId=521 and age = 30;
EXPLAIN SELECT * FROM student WHERE classId=521 and age = 30;
EXPLAIN SELECT * FROM student WHERE name='DzQJIv' and classId=521;
对于联合索引idx_age_name_classId,以上3条语句,第三个不能使用到索引
(2)计算、函数导致索引失效
创建索引:CREATE INDEX idx_name ON student(name);
EXPLAIN SELECT * FROM student WHERE student.name LIKE 'abc%';(使用到索引)
EXPLAIN SELECT * FROM student WHERE LEFT(student.name,3) = 'abc';(索引列使用到函数,索引失效)
创建索引:CREATE INDEX idx_stuno ON student(stuno);
EXPLAIN SELECT SQL_NO_CACHE id, stuno, NAME FROM student WHERE stuno = 900000;
(使用到索引)
EXPLAIN SELECT SQL_NO_CACHE id, stuno, NAME FROM student WHERE stuno+1 = 900000;(索引列计算导致索引失效)
(3)类型转换索引失效
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE name=123;(name=123发生类型转换,导致索引失效)
(4)范围条件右边的列索引失效
EXPLAIN SELECT * FROM student WHERE student.age=30 AND student.classId>20 AND student.name = 'abc' ;(此处联合索引的name字段就失效了)
索引:CREATE INDEX idx_age_classId_name ON student(age,classId,name);
(5)不等于(!= 或者<>)导致索引失效
(6)is null可以使用索引,is not null无法使用索引
EXPLAIN SELECT * FROM student WHERE age IS NOT NULL;
(is not null导致索引失效)
(7)like以通配符%开头索引失效
EXPLAIN SELECT * FROM student WHERE age LIKE '%1';(左模糊匹配会 导致索引失效)
(8)OR 前后存在非索引的列,索引失效
EXPLAIN SELECT * FROM student WHERE age = 10 OR classid = 100;(此时只有age是索引列,索引失效)
EXPLAIN SELECT * FROM student WHERE age = 10 OR classid = 100;(给classid也加上索引,索引生效)
2. EXPLAIN各列作用
2.1 table
查询的每一行记录都对应着一个单表。
eg:EXPLAIN SELECT * FROM s1;
eg:EXPLAIN SELECT * FROM s1 INNER JOIN s2;
2.2 id
在一个大的查询语句中每个SELECT关键字都对应一个唯一的id
eg:EXPLAIN SELECT * FROM s1 WHERE key1 = 'EwuHdw';
eg:EXPLAIN SELECT * FROM s1 INNER JOIN s2;
eg:EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'EwuHdw';
eg:EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key2 FROM s2 WHERE common_field = 'EwuHdw');(查询优化器可能对涉及子查询的查询语句进行重写,转变为多表查询的操作)
小结:
- id如果相同,可以认为是一组,从上往下顺序执行
- 在所有组中,id值越大,优先级越高,越先执行
- id号每个号码,表示一趟独立的查询, 一个sql的查询趟数越少越好
2.3 select_type
SELECT关键字对应的那个查询的类型
eg:EXPLAIN SELECT * FROM s1;(查询中不包含union或者子查询的都算SIMPLE)
eg:EXPLAIN SELECT * FROM s1 INNER JOIN s2;(连接查询也算SIMPLE)
eg:EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;
eg:EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'EwuHdw';(不相关子查询--SUBQUERY)
eg:EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE s1.key2 = s2.key2) OR key3 = 'EwuHdw';(相关子查询-DEPENDENT SUBQUERY)
2.4 partitions
匹配的分区信息
2.5 type
针对单表的访问方法,完整的访问方法如下:system, const, eq_ref, ref, fulltext, ref_or_null, index_merge, unique_subquery, index_subquery, range, index, ALL
- system
当表中只有一条记录,且该表使用的存储引擎统计的数据是精确的,如MyISAM,memory,那么对该表的访问方法就是system
eg:CREATE TABLE t(i int) Engine=MyISAM;
INSERT INTO t VALUES(1); EXPLAIN SELECT * FROM t;
- const
根据主键或者唯一二级索引列与常数进行等值匹配时,为const
eg:EXPLAIN SELECT * FROM s1 WHERE id = 10031;
eg:EXPLAIN SELECT * FROM s1 WHERE key2 = 10996;(这里key2是唯一二级索引)
- eq_ref
在连接查询时,被驱动表通过主键或唯一二级索引进行等值匹配时,为eq_ref
eg:EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id = s2.id; (从执行计划的结果中可以看出,MySQL打算将s2作为驱动表,s1作为被驱动表,重点关注s1的访问方法是 eq_ref ,表明在访问s1表的时候可以 通过主键的等值匹配来进行访问。)
- ref
通过普通的二级索引与常量进行等值匹配,为ref
eg:EXPLAIN SELECT * FROM s1 WHERE key1 = 'EwuHdw';
- fulltext
全文索引
- ref_or_null
对普通的二级索引与常量进行等值匹配查询,该索引列的值也可以是“NULL”时,为ref_or_null
eg:EXPLAIN SELECT * FROM s1 WHERE key1 = 'EwuHdw' OR key1 IS NULL;
- index_merge
索引合并的方式
eg:EXPLAIN SELECT * FROM s1 WHERE key1 = 'EwuHdw' OR key3 = 'EwuHdw';
- unique_subquery
针对在一些包含“IN”子查询的查询语句中,如果查询优化器决定将in子查询转换为exists子查询,而且子查询 可以使用到等值进行匹配,那么该子查询执行计划的type就是“unique_subquery”
eg:EXPLAIN SELECT * FROM s1 WHERE key2 IN (SELECT id FROM s2 where s1.key1 = s2.key1) OR key3 = 'a';
- range
如果使用索引获取某些范围区间的记录,则为range
eg:EXPLAIN SELECT * FROM s1 WHERE key1 IN ('vWvogO', 'WeIbjO', 'AzZviA');
- index
当我们可以使用索引覆盖,但需要扫描所有的索引记录时,为index
eg:EXPLAIN SELECT key_part2 FROM s1 WHERE key_part3 = 'vWvogO';
- ALL
全表扫描
eg:EXPLAIN SELECT * FROM s1;
小结:type值需要达到的目标,至少要达到range级别要求是ref级别,最好是const级别
2.6 possible_keys和key
possible_keys:可能用到的索引
key:实际用到的索引
eg:EXPLAIN SELECT * FROM s1 WHERE key1 > 'vWvogO' AND key3 = 'vWvogO';
2.7 key_len
实际使用到的索引长度,检查是否充分利用上了索引
eg:EXPLAIN SELECT * FROM s1 WHERE id = 10031;
eg:EXPLAIN SELECT * FROM s1 WHERE key_part1 = 'vWvogO';
2.8 ref
当使用索引列等值查询时,与索引列进行等值匹配的对象信息
eg:EXPLAIN SELECT * FROM s1 WHERE key1 = 'EwuHdw';(等值匹配的是常量)
eg:EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id = s2.id;
eg:EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s2.key1 = UPPER(s1.key1);
2.9 rows
预估的需要读取的记录条数,值越小越好
eg:EXPLAIN SELECT * FROM s1 WHERE key1 > 'vWvogO';
2.10 filtered
某个表经过搜索条件过滤后剩余记录条数的百分比,值越大越好
2.11 Extra
一些额外的信息,更准确的理解MySQL到底如何执行查询语句
eg:EXPLAIN SELECT 1;
eg:EXPLAIN SELECT * FROM s1 WHERE 1 != 1;
eg:EXPLAIN SELECT * FROM s1 WHERE common_field = 'vWvogO';
eg:EXPLAIN SELECT MIN(key1) FROM s1 WHERE key1 = 'abcdefg';(没有记录)
eg:EXPLAIN SELECT key1 FROM s1 WHERE key1 = 'vWvogO';(使用到覆盖索引)
eg:EXPLAIN SELECT * FROM s1 WHERE key1 > 'z' AND key1 LIKE '%b';(索引条件下推)
eg:EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.common_field = s2.common_field;
(连接查询执行过程中,被驱动表不能有效的利用索引加快访问速度)
eg:EXPLAIN SELECT * FROM s1 ORDER BY common_field LIMIT 10;(排序未使用到索引,需要规避)
eg:EXPLAIN SELECT DISTINCT common_field FROM s1;(使用临时表)
3.查询优化
3.1 关联查询优化
- 保证被驱动表的join字段添加了索引
- 需要join的字段,数据类型保持绝对一致
- left join时,选择小表(小的结果集)作为驱动表,大表(大的结果集)作为被驱动表
- inner join时,MySQL会自动将小结果集的表作为驱动表
- 能够直接多表关联的尽量直接关联,不用子查询(减少查询的趟数)
- 不建议使用子查询,建议将子查询SQL拆开结合程序多次查询或者使用join来代替子查询
- 衍生表建不了索引
3.2 子查询优化
子查询可以通过sql实现比较复杂的查询,但子查询的效率并不高,原因:
(1)执行子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表,然后外层查询语句从临时表中查询记录。查询完毕后,再撤销这些临时表,这样会消耗过多的cpu和io,产生大量的慢查询。
(2)子查询的结果集存储的临时表,不会存在索引,查询性能会受到一定的影响
(3)对于返回结果集比较大的子查询,其对查询性能的影响也就越大
总结:在MySQL中,尽量使用join查询来代替子查询,连接查询不需要建立临时表,其速度比子查询快,如果查询使用索引的话,性能就会更好
3.3 排序优化
(1)order by的列尽量使用索引列,如果where和order by使用的是相同的列,就建单列索引,如果不相同,就建联合索引
(2)无法使用索引时,需要对FileSort方式进行调优
MySQL之索引,执行计划及SQL优化相关推荐
- oracle试图执行计划,Oracle SQL优化与调优之显示执行计划(上)
通过查询语句显示计划 通过查询语句从这些视图里面读出执行计划并作格式化输出的方法都非常相似,我们这里以 sql_plan 为例给出示例. 通过包 DBMS_XPLAN 显示计划 这个包可以根据我们选择 ...
- MySQL中的执行计划
MySQL中的执行计划 在MySQL中可以通过explain关键字模拟优化器执行SQL语句,从而知道MySQL是如何处理SQL语句的: 一.Mysql整个查询执行过程 客户端向MySQL服务器发送一 ...
- oracle执行脚本顺序执行吗,【ORACLE】记录通过执行Oracle的执行计划查询SQL脚本中的效率问题 - 不及格的飞鱼...
记录通过执行Oracle的执行计划查询SQL脚本中的效率问题 问题现象: STARiBOSS5.8.1R2版本中,河北对帐JOB执行时,无法生成发票对帐文件. 首先,Quartz表达式培植的启动时间为 ...
- MySQL 的索引是什么?怎么优化?
转载自 MySQL 的索引是什么?怎么优化? 摘要: 索引对大数据的查询速度的提升是非常大的,Explain可以帮你分析SQL语句是否用到相关索引. 索引类似大学图书馆建书目索引,可以提高数据检索的 ...
- 引用:初探Sql Server 执行计划及Sql查询优化
引用:初探Sql Server 执行计划及Sql查询优化 原文:引用:初探Sql Server 执行计划及Sql查询优化 初探Sql Server 执行计划及Sql查询优化 收藏 MSSQL优化之-- ...
- 简单介绍oracle执行计划,Oracle性能优化之oracle中常见的执行计划及其简单解释
一.访问表执行计划 1.table access full:全表扫描.它会访问表中的每一条记录(读取高水位线以内的每一个数据块). 2.table access by user rowid:输入源ro ...
- Oracle执行计划。RBO优化器和CBO优化器。TABLE ACCESS FULL,TABLE ACCESS BY INDEX ROWID,TABLE ACCESS BY INDEX SCAN
文章目录 通过PL/SQL Developer查看查询的执行计划 1. 什么是执行计划 2. 配置执行计划需要显示的项 3执行计划的常用列字段解释 4. 使用执行计划 5. 查看执行计划 5.1 执行 ...
- MySQL中explain执行计划中额外信息字段(Extra)详解
SQL执行计划是经过优化器决策,产生的SQL在数据库内部执行的访问路径计划: 由如下语法得到: explain select col1,col2 from t1..; desc select col1 ...
- mysql 执行计划不对_关于mysql主从查询执行计划不一致问题的分析
最近面试过程中被面试官抛了一个问题,说曾经有一个线上出现的奇怪的问题,主库和从库各种配置是一致的,当数据量比较大的时候,某些时候同样的查询,在从库里的执行计划执行成功了,而主库里没有执行这个执行计划, ...
最新文章
- [ExtJS5学习笔记]第五节 使用fontawesome给你的extjs5应用添加字体图标
- mysql asyn 示例
- 【快乐水题】997. 找到小镇的法官
- python打开figure对象_Python ——绘图 plt.figure()的使用
- Halcon自定义函数封装方法(全网最详细)
- python 类变量(属性)和实例变量(属性
- Xtrabackup备份与恢复
- 愿你的指下有代码,眼里有星辰
- vue设置textarea最大字数_【Vue 学习】 Vue常用系统指令
- 【渝粤教育】国家开放大学2018年春季 0631-21T动物常见病防治 参考试题
- Linq to sql 语法方法示例
- 学计算机的学数学分析吗,学计算机专业是不是对数学的要求很高?
- 联想P340加显卡白屏,降级BIOS恢复正常。
- 有关git commit --amend的用法及若干个问题
- 安装office2013报安装程序找不到OneNote.zh-cn、安装源不存在
- FusionInsight
- CSS3实现自适应的聊天气泡
- 如何在代码中判断当前设备是iPhone 4/4S还是iPhone 5?
- 谷歌收购七家科技公司 秘密打造机器人帝国
- PreCreateWindow作用
热门文章
- 申请计算机课代表,课代表申请书的格式是怎样的啊???
- php 粘性表单功能,php 粘性表单验证
- 允许在CAD中操作超链接!Aspose.CAD最新版v19.9新功能你都了解吗?
- 如果你身边有程序员 今天对他好一点
- win8“400 bad request”能登QQ,无法上网解决办法d
- 12AU7设计中的一个小技巧
- PDFBox加密和解密PDF文件
- 三井住友加入R3 Marco Polo区块链网络
- 《Qt5:同一个界面多窗口或者多页面切换(QStackedWidget)》
- C#数字金额转人民币大写金额的实现