1. MySQL 架构
1.1 MySQL 简介
mysql内核
sql优化攻城狮
mysql服务器的优化
各种参数常量设定
查询语句优化
主从复制
软硬件升级
容灾备份
sql编程
1.2 MySQL逻辑架构介绍
1.2.1第1层:连接层
** 系统(客户端)访问 MySQL 服务器前,做的第一件事就是建立 TCP 连接。 经过三次握手建立连接成功后, MySQL 服务器对 TCP 传输过来的账号密码做身份认证、权限获取。
- 用户名或密码不对,会收到一个Access denied for user**错误,客户端程序结束执行
- 用户名密码认证通过,会从权限表查出账号拥有的权限与连接关联,之后的权限判断逻辑,都将依 赖于此时读到的权限
TCP 连接收到请求后,必须要分配给一个线程专门与这个客户端的交互。所以还会有个线程池,去走后 面的流程。每一个连接从线程池中获取线程,省去了创建和销毁线程的开销。
1.2.2 第2层:服务层
- SQL Interface: SQL接口
- 接收用户的SQL命令,并且返回用户需要查询的结果。比如SELECT … FROM就是调用SQL Interface
- MySQL支持DML(数据操作语言)、DDL(数据定义语言)、存储过程、视图、触发器、自定 义函数等多种SQL语言接口
- Parser: 解析器
- 在解析器中对 SQL 语句进行语法分析、语义分析。将SQL语句分解成数据结构,并将这个结构 传递到后续步骤,以后SQL语句的传递和处理就是基于这个结构的。如果在分解构成中遇到错 误,那么就说明这个SQL语句是不合理的。
- 在SQL命令传递到解析器的时候会被解析器验证和解析,并为其创建 语法树 ,并根据数据字 典丰富查询语法树,会 验证该客户端是否具有执行该查询的权限 。创建好语法树后,MySQL还 会对SQl查询进行语法上的优化,进行查询重写。
- Optimizer: 查询优化器
- SQL语句在语法解析之后、查询之前会使用查询优化器确定 SQL 语句的执行路径,生成一个 执行计划 。
- 这个执行计划表明应该 使用哪些索引 进行查询(全表检索还是使用索引检索),表之间的连 接顺序如何,最后会按照执行计划中的步骤调用存储引擎提供的方法来真正的执行查询,并将 查询结果返回给用户。
- 它使用“ 选取-投影-连接 ”策略进行查询。例如:
这个SELECT查询先根据WHERE语句进行 选取 ,而不是将表全部查询出来以后再进行gender过 滤。 这个SELECT查询先根据id和name进行属性 投影 ,而不是将属性全部取出以后再进行过 滤,将这两个查询条件 连接 起来生成最终查询结果。SELECT id,name FROM student WHERE gender = '女';
- Caches & Buffers**: 查询缓存组件**
- MySQL内部维持着一些Cache和Buffer,比如Query Cache用来缓存一条SELECT语句的执行结 果,如果能够在其中找到对应的查询结果,那么就不必再进行查询解析、优化和执行的整个过 程了,直接将结果反馈给客户端。
- 这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key缓存,权限缓存等 。
- 这个查询缓存可以在 不同客户端之间共享 。
- 从MySQL 5.7.20开始,不推荐使用查询缓存,并在 MySQL 8.0中删除 。
小故事: 如果我问你9+8×16-3×2×17的值是多少,你可能会用计算器去算一下,最终结果35。如果再问你一遍9+8×16- 3×2×17的值是多少,你还用再傻呵呵的再算一遍吗?我们刚刚已经算过了,直接说答案就好了。
1.2.3 第3层:引擎层
插件式存储引擎层( Storage Engines),真正的负责了MySQL中数据的存储和提取,对物理服务器级别 维护的底层数据执行操作 ,服务器通过API与存储引擎进行通信。不同的存储引擎具有的功能不同,这样 我们可以根据自己的实际需要进行选取。
MySQL 8.0.25默认支持的存储引擎如下:
1.2.4 存储层
所有的数据,数据库、表的定义,表的每一行的内容,索引,都是存在 文件系统 上,以 文件 的方式存 在的,并完成与存储引擎的交互。当然有些存储引擎比如InnoDB,也支持不使用文件系统直接管理裸设 备,但现代文件系统的实现使得这样做没有必要了。在文件系统之下,可以使用本地磁盘,可以使用 DAS、NAS、SAN等各种存储系统。
1.2.5 小结 MySQL架构图本节开篇所示。下面为了熟悉SQL执行流程方便,我们可以简化如下:
简化为三层结构:
- 连接层:客户端和服务器端建立连接,客户端发送 SQL 至服务器端;
- SQL 层(服务层):对 SQL 语句进行查询处理;与数据库文件的存储方式无关;
- 存储引擎层:与数据库文件打交道,负责数据的存储和读取。
1.3 存储引擎
- innodb 和 MyISAM对比:
- Percona:阿里和淘宝用什么?
- Percona 为 MysQL数据库服务器进行了改进,在功能和性能上较 MySQL 有着很显著的提升。该版本提升了在高负载情况
下的 InnoDB 的性能、为 DBA 提供一些非常有用的性能诊断工具:另外有更多的参数和命令来控制服务器行为。 - 该公司新建了一款存储引擎叫xtradb完全可以替代innodb,并且在性能和并发上做得更好,
- 阿里巴巴大部分mysql数据库其实使用的percona的原型加以修改。
- AliSql+AliRedis
- Percona 为 MysQL数据库服务器进行了改进,在功能和性能上较 MySQL 有着很显著的提升。该版本提升了在高负载情况
2. 索引优化分析
2.1 SQL性能下降原因
- 表象:
- 性能下降SQL慢
- 执行时间长
- 等待时间长
- 原因:
- 查询语句写的烂
- 索引失效
- 单值索引
建过索引之后会在底层进行排序,所以会优化查找速度create index idx_user_name on user(name)
- 复合索引
create index idx_user_nameEmail on user(name,email)
- 对多个字段建立索引
- 哪些字段建立索引?
- 单值索引
- 关联查询太多join(设计缺陷或不得己的需求)
- 服务器调优及各个参数设置(缓冲、线程数等)
2.2 SQL 执行顺序:
- 手写顺序:
SELECT DISTINCT <select_1ist> FROM <left_table> <join_type > JOIN <right_table> ON <join_condition > WHERE <where_condition> GROUP BY <group_by_list> HAVING <having condition> ORDER BY <order_by_condition> LIMIT <1imit_number>
- 机读顺序:
FROM <left_table> <join_type > ON <join_condition > <join_type > JOIN <right_table> WHERE <where_condition> GROUP BY <group_by_list> HAVING <having_condition> SELECT DISTINCT <select_1ist> ORDER BY <order_by_condition> LIMIT <1imit_number>
- 总结(鱼刺图)
2.3 七种Join
- 七种连接图片
2.4 索引
- 什么是索引:
- MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。可以得到索引的本质:索引是数据结构。
- 你可以简单理解为〝排好序的快速查找数据结构”。
- 索引的目的在于提高查询效率,可以类比字典,
- 索引会影响查找和 order By 的排序
- 上我们平常所说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引。当然,除B+树这种类型的索引之外,还有**哈希索引(hashIndex)**等。
- **在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是素引。**下图就是一种可能的索引方式示例:
- 数据做软删除的原因:为数据分析服务;为了索引连续
- 如果经常删除数据的话,索引指向的对象位置会发送变化,索引会指错。需要索引重建。
- 增删慢,修改快,因为也需要修改索引
- 一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘
- 索引优势与劣势:
- 优势:
- 类似大学图书馆建书目索引,提高数据**检索的效率**,降低数据库的10成本
- 通过索引列对数据进行排序,降低数据**排序的成本**,降低了CPU的消耗
- 劣势:
- 实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的
- 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、 UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息
- 索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询。
- 优势:
- 索引分类:
- 单值索引:
- 即一个索引只包含单个列,一个表可以有多个单列索引
- 复合索引优于单值索引
- 一张表尽量不要超过 5 个索引
- 唯一索引:索引列的值必须唯一,但允许有空值
- 复合索引:即一个索引包含多个列
- 基本语法:
- 创建:
CREATE [UNIQUE] INDEX indexName ON mytablekfcolumnname(length)) ALTER mytable ADD [UNIQUE] INDEX [indexName] ON (columnname(length))
- 删除:
DROP INDEX [indexName] ON mytable;
- 查看:
SHOW INDEX FROM table_name
- 使用 AlTER 命令:
# 4种方式来添加数据表的索引 ALTER TABLE tbLname ADD PRIMARY KEY (Solumn_ list) # 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。 ALTER TABLE tbLname ADD UNIQUE index_name (column_list) # 这条语句创建素引的值必须是唯一的(除了NULL外,NULL可能会出现多次) ALTER TABLE tbLname ADD INDEX index_name (column_list) #添加普通索引,索引值可出现多次。 ALTER TABLE tbl_ name ADD FULLTEXT index _name (column_list) #该语句指定了素引为 FULLTEXT,用于全文素引。
- 创建:
- 单值索引:
- 索引结构(后三个了解即可)
- B 树:
- 真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有素引,每个数据项都要发生一次lO,那么总共需要百万次的IO,显然成本非常非常高。
- Hash 索引
- full-text 全文索引
- R-树索引
- B 树:
- 哪些情况需要创建索引
- 主键自动建立唯一索引
- 频繁作为查询条件的字段应该创建索引
- 查询中与其它表关联的字段,外键关系建立索引
- 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
- 查询中统计或者分组(group by)字段:后面会有 demo
- 索引创建备注:
- 单键/组合索引的选择问题,who?(在高并发下倾向创建组合索引)
- 频繁更新的字段不适合创建索引:因为每次更新不单单是更新了记录还会更新索引
- Where条件里用不到的字段不创建索引
- 哪些情况下不要创建索引
- 表记录太少
- 经常增删改的表
- Why:提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件
- 数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据列建立索引。注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
- 例如国籍字段或者性别
- 假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。素引的选择怢是指泰引列中不同值的数县与表中记录数的比。如果一个表中有2000条记录,表索引列有1980个不同的值,那么这个索引的选择性就是1980/2000-0.99。一个索引的选择性越接近于1,这个索引的效率就越高。
2.5 性能分析(Explain)
- 总览:
- MySql Query Optimizer
- Mysql中有专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为户端请求的Query提供他认为最优的执行计划(他认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分最耗费时间
- 当客户端向MySQL 请求一条Query,命令解析器模块完成请求分类,区别出是 SELECT 并转发给MySQL Query Optimizer时,MysQL Query Optimizer 首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。 并对 Query 中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等。然后分析 Query 中的 Hint 信息(如果有),看显示Hint信息是否可以完全确定该Query 的执行计划。如果没有 Hint 或Hint 信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据 Query 进行写相应的计算分析,然后再得出最后的执行计划。
- MySQL常见瓶颈
- ICPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候
- IO:磁盘I/O瓶颈发生在装入数据远大于内存容量的时候
- 服务器硬件的性能瓶颈:top,free, iostat和vmstat来查看系统的性能状态
- Explain:一个新的分析工具(执行计划)
- MySql Query Optimizer
- Explain:
- 是什么?简称执行计划
- 使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈
- 用法:Explain + SQL
- 能做什么:
- 表的读取顺序
- 数据读取操作的操作类型
- 哪些索引可以使用
- 哪些索引被实际使用
- 表之间的引用
- 每张表有多少行被优化器查询
- explain 字段:
id select_type table type possible_keys key key_len ref rows Extra - Id:
- select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
- 值有三种情况:
- id相同,执行顺序由上至下
- id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
- id相同不同,同时存在:数字大的优先级高
- id相同,执行顺序由上至下
- table:显示数据关于那张表的
- derived:衍生表
- Select_type:
- 值有哪些:
- SIMPLE:简单的 select 查询,查询中不包含子查询或者UNION
- PRIMARY:查询中若包含任何复杂的子部分,最外层查询则被标记为
- SUBQUERY:在SELECT或WHERE列表中包含了子查询
- DERIUED:在FROM列表中包含的子查询被标记为DERIVED(行生)MysQL会递归执行这些子查询,把结果放在临时表里。
- UNION:若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
- UNION RESULT:合并结果,两个相同字段的查询结果集合
- 查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询
- 值有哪些:
- type:
- 显示查询使用了何种类型,从最好到最差依次是:system>const>eq_ref>ref>range>index>ALL。一般来说,得保证查询至少达到range级别,最好能达到ref。
- 值与意思:
- system:表只有一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也可以忽略不计
- const:表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快如将主键置于where列表中,MySQL就能将该查询转换为一个常量
子查询里面查 id=1,是一个 const 常量查询;子查询生成的表就一条记录,就变成 system - eg_ ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
select * from table where id = 1 # id 是主键
- ref:非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体
select * from table where name = '小明'
- range:只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引一般就是在你的where语句中出现了between、<、>、in等的查询这种范围扫描索引扫描比全表扫描要好,啊为它只需要开始于索引的某一点,而结束语另一点,不用扫描全部索引。
select * from table where id between 30 and 60
- index:Full Index Scan, index与ALL区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。(也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
select id from table # id是主键,全索引扫描
- all:全表扫描,性能非常差(对查询的字段不建立索引就是这个效果)
select * from t1 where column_without_index = '';
- possible_keys:
- 显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引 则该索引将被列出,但不一定被查询实际使用
- mysql初步判断可能会用哪些索引,并不一定会使用,只是推测
- key: 实际使用的索引。如果为NULL,则没有使用索引。查询中若使用了覆盖索引,则该索引仅出现在key列表中
- key 为 null要么就是没有建立索引,如果建立了没有使用就是索引失效。
- 覆盖索引:就是select的数据列只用从索引中就能够取得,不必读取数据行,MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖。注意是一个索引匹配查询字段。如果对查询的每个字段都分别建立了不同的索引,不能叫覆盖索引。
- Key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出 - ref:显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值
这里面 ref 的值代表我在比较的时候我用了什么值作为等号右边的值,“ac“是 const;t2.col1就是 ref - rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数
- Extra:包含不适合在其他列中显示但十众重要的额外信息
- Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。 MySQL中无法利用索引究成的排序操作称为〝文件排序”。(出现这个东西不好)
这里产生 Using filesort 因为排序没有用到创建好的索引,而是另起炉灶进行了排序。 - Using temporary:使了用临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序 order by 和分组查询 group by。(出现这个东西不好)
- using index:
- 表示相应的select操作中使用了覆盖索引 (Covering Index),避免访问了表的数据行,效率不错!
- 如果同时出现using where,表明索引被用来执行索引键值的查找:
- 如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。
- 覆盖索引(Covering Index),一说为索引覆盖。
- 理解方式一:就是select的数据列只用从索引中就能够取得,不必读取数据行,MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖。
- 理解方式二:索引是高效找到行的一个方法,但是一般数据库也能使用素引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了。一个索引包含了(或覆盖了)满足查询结果的数据就叫做覆盖索引。
- using where:表示查询执行时需要进一步筛选满足WHERE条件的行。这通常发生在没有合适的索引或无法使用索引进行覆盖扫描的情况下。数据库需要检查每一行的数据,并使用WHERE条件进行过滤。
- using join buffer:使用了连接缓存:
- impossible where:where子句的值总是false,不能用来获取任何元组
- select tables optimized away:在没有GROUPBY子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。
- distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作
- Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。 MySQL中无法利用索引究成的排序操作称为〝文件排序”。(出现这个东西不好)
- Id:
2.6 索引优化
- 索引分析:
- 单表:
- 查询 category_id 为1且 comments 大于1 的情况下,views 最多的 article_id。
此时仅仅能完成,没有建立索引,type是 all,extra 还出现了 using filesortEXPLAIN SELECT id,author. id FROM article WHERE category_id = 1 AND comments >1 ORDER BY views DESC LIMIT 1;
- 新建复合索引
分析:此时有了索引,type 是 range,但是 Extra 还是 Using filesort,因索引是create index idx_article_ccv on article(category_id,comments,views);
idx_article_ccv
在article(category_id, comments, views)
上。在这个索引中,第一个字段是category_id
,第二个是comments
,第三个是views
。所以,在这个查询中,首先根据category_id
进行筛选,然后根据comments
进行筛选,这两步都可以利用索引。然而,当你按views
排序时,这个操作不能直接利用索引,因为它是索引的第三个字段,前面的字段并没有完全涵盖WHERE子句的条件(comments > 1
是个范围查询,而不是具体值),所以它会进行filesort
。 - 删除索引
drop index idx_article_ccv on article
- 建立新索引,不包括 comment
结果:type 是 ref,使用了 key,extra 是 using where,ref 比较的是 constcreate index idx_article_cv on article(category_id,views);
- 总结:第一个优化案展现了复合索引并不是字段越多越好,范围会导致索引失效,这个在后面讲。
- 查询 category_id 为1且 comments 大于1 的情况下,views 最多的 article_id。
- 两表:
-
分析;两个查询type 是 allexplain select * from class left join book on class.card = book.card
- 尝试在 book 上加索引
结果:加索引的查询 type 变成 ref,key 是 Y,行数也有所减少alter table `book` add index Y(`card`)
- 删除 book 的索引再尝试加在 class 上
结果:type 是 index,rows 没有减少,key 是 Y,实际查找并未减少drop index Y on book alter table `class` add index Y(`card`)
这是由左连接特性决定的。LEFT JOIN 条件用于确定如何从右表搜索行,左边一定都有,而去从右表进行搜索,所以需要建立在右表会提升效率,所以右边是我们的关键点,一定需要建立素引
索引如果已经建立好,也可以交换表的位置, - 对于右连接,右边的部分都有,索引建立在左表
- 总结:连接查询中,在哪个表需要进行部分获取的搜索,就建立在哪个表。左连接索引建右表,右连接索引建左表
-
- 三表:
-
分析:type 全是 all,没有索引,并Extra 出现了 join bufferselect * from class inner JOIN book ON class.card=book.card inner JOIN phone ON book.card=phone.card
- 对 phone 和 book 建立索引
结果:建立索引的两个表type变成 ref,rows 减少,key 非空alter table `book` add index y(`card`) alter table `phone` add index z(`card`)
- 结论:join 语句优化:
- 尽可能减少Join语句中的NestedLoop的循环总次数:“永远用小结果集驱动大的结果集”。
- 优先优化NestedLoop的内层循环;
- 保证Join语句中被驱动表上Join条件字段己经被索引;
- 当无法保证被驱动表的Join条件字段被索引且内存资源充足的前提下,不要太吝惜JoinBuffer的设置;
-
- 单表:
- 索引失效(应该避免)
- 全值匹配我最爱:
- 当一个复合索引里面所有的属性都进行了where 条件判断,此时精度最高。
- 例如:索引(name,age,pos)。
- 如果只使用name,key_len是 74;
- 使用 name,age 做判断 key_len是 78;
- 三个全用是 140
- 如果不是有 name 直接使用后两个,会造成索引失效,就是第二条左前缀
- 最佳左前缀法则:
- 如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。
- 例如:索引(name,age,pos)。
- 没有name 作为左前缀,则索引会直接失效;
- 使用name,和 pos 跳过 age,则 pos 索引失效,相当于只加了 name 索引
- 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
这样会导致索引完全失效,key 为空,type 为 all# 举例 select * from staffs where left(name,4) = 'July'
- 存储引擎不能使用索引中范围条件右边的列(包括大于、小于、in、like)
第二个查询:age 这里有用到,但是manager 失效。type 退化成 range- 例如:索引(A, B, C)。
- 对于查询
WHERE A = 1 AND B = 2 AND C = 3
,这个查询可以充分利用索引(A, B, C)
。 - 对于查询
WHERE A = 1 AND B > 2 AND C = 3
,这个查询只能利用索引的(A, B)
部分,因为B > 2
是一个范围查询,它右边的字段C
不能使用索引优化。 - 对于查询
WHERE A > 1 AND B = 2 AND C = 3
,这个查询只能利用索引的A
字段,因为A > 1
是一个范围查询,它右边的所有字段都不能使用索引优化。
- 对于查询
- 例如:索引(A, B, C)。
- 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select *
extra 出现了 using index,效率更高 - mysql 在使用不等于(!=或者)的时候无法使用索引会导致全表扫描
type 变成 all - is null,is not null 也无法使用索引
- like以通配符开头(%abc.”)mysql索引失效会变成全表扫描的操作
- 结论:%写在右边不会失效,尽量写在右边
- 问题:解决like '%字符串%'时索引不被使用的方法? 利用覆盖索引
解决:如果一定要用%aa%,则把 select * 改为 select 覆盖索引属性。但是,一旦有不是索引覆盖的属性,则索引失效
- 字符串不加单引号索引失效
mysql 会将 int 的 2000 自动转换成 varchar 的 2000,但是会报一个警报。 - 少用or,用它来连接时会索引失效
key 为 null 了,索引失效 - 小总结:
- 带头大哥不能死,中间兄弟不能断(最佳左前缀)
- 索引之上无计算
- like 百分加右边
- 范围之后全失效
- 字符串上里有引号
- 全值匹配我最爱:
- 面试题目:
- where 条件 1 and 条件2 and 条件3 :三个条件的顺序不会影响结果,mysql 的优化器会自动调整顺序。不过最好和索引顺序保持一直,减少优化。
- 题目二
只有两个索引生效,前两个生效;但是 c3 的索引也用到了,进行了排序 - 题目三
和上面一样 - 题目四
由于跨过了 c3,导致 c4 索引不能用于排序,所以产生了 filesort - 题目五
explain select * from testo3 where c1=a1’ and c5=a5’ order by c2,c3,
只用c1一个字段素引,但是c2、c3用于排序,无filesort - 题目六
这里先排3 再排 2,和索引的排序顺序是不同的,所以需要重新排,filesort,寄 - 题目七
这里也违反了顺序,但是缺没有 filesort,因为有一个 c2 与常量的比较,先完成了 c2 的比较之后,order by c3 的顺序得以连贯,c2 此时已经是一个常量了,导致 order by c2 失效,所以没有出现 filesort - 题目八
只有一个索引生效,group by 不会利用索引 - 题目九
与索引顺序不同,导致重新建立临时表,并且产生文件排序
group by 基本上都需要进行排序,会有哈时表产生,group by 几乎和 order by一致
- 一般性建议:
- 对于单键索引,尽量选择针对当前query过滤性更好的索引
- 在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前(左)越好。
- 在选择组合索引的时候,尽量选择可以能够包含当前query中的where字句中更多字段的索引
- 尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的