标题
- 一、性能下降SQL慢的原因 (执行时间长 等待时间长)
- 二、常见通用的join查询
- 三、索引简介
- 四、性能分析 (★)
- 五、索引优化 (★)
- (1) 索引分析
- (2) 索引失效 (应该避免)
- 索引失效的的一些案例
- ① 全值匹配我最爱
- ② 最佳左前缀法则 ( 如果索引了多例,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。)
- ③ 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
- ④ 存储引擎不能使用索引中范围条件右边的列
- ⑤ 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select*
- ⑥ mysql在使用不等于( != 或者 <>)的时候无法使用索引可能会导致全表扫描
- ⑦ is null,is not null 也无法使用索引
- ⑧ like以通配符开头('%abc...')mysql索引失效会变成全表扫描操作
- ⑨ 字符串不加单引号索引失效
- ⑩ 少用or,用它连接时会索引失效
- 小总结
- 索引题目练习
- 面试题
- (3) 一般性建议
- 个人疑惑总结 --- 全值匹配 和 覆盖索引
----------------------- 建表语句 ----------------------------
一、性能下降SQL慢的原因 (执行时间长 等待时间长)
- 查询语句写的差。
- 索引失效:索引建了,但是没有用上。
- 关联 查询太多join(设计缺陷或者不得已的需求)。
- 服务器调优以及各个参数的设置(缓冲、线程数等)。
二、常见通用的join查询
(1) SQL执行顺序
手写顺序
机读顺序
总结
(2) Join图
三、索引简介
(1) 什么是索引
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高校获取数据的数据结构。
可以得到索引的本质:索引是 数据结构
你可以简单理解为"排好序的快速查找数据结构"。
数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引。
一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以文件形式存储在硬盘上
我们平时所说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉树)结构组织的索引。其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引。当然,除了B+树这种类型的索引之外,还有哈希索引(hash index)等。
(2) 索引的优势
- 类似大学图书馆建书目索引,提高数据检索效率,降低数据库的IO成本
- 通过索引列对数据进行排序,降低数据排序成本,降低了CPU的消耗
(3) 索引的劣势
- 实际上索引也是一张表,该表保存了主键和索引字段,并指向实体表的记录,所以索引列也是要占用空间的
- 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如果对表INSERT,UPDATE和DELETE。
因为更新表时,MySQL不仅要存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息 - 索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立优秀的索引,或优化查询语句
(4) mysql 索引分类
建议一张表索引不要超过5个 优先考虑复合索引
单值索引
即一个索引 只包含单个列,一个表可以有多个单列索引
唯一索引
索引列的值必须唯一,但 允许有空值
复合索引
即 一个索引包含多个列
基本语法
- 创建
方式一:
CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length));
方式二:
ALTER TABLE mytable ADD [UNIQUE] INDEX [indexName](columnname(length));
如果是CHAR,VARCHAR类型,length可以小于字段实际长度;
如果是BLOB和TEXT类型,必须指定length。
- 删除
DROP INDEX [indexName] ON mytable;
- 查看
SHOW INDEX FROM table_name\G
- 使用ALTER命令
(5) mysql 索引结构
- BTree索引
Btree索引 (或Balanced Tree),是一种 很普遍的数据库索引结构,oracle默认的索引类型。其 特点 是 定位高效、利用率高、自我平衡,特别适用于高基数字段,定位单条或小范围数据非常高效。理论上,使用Btree在 亿条数据与100条数据中定位记录的花销相同。
(就和二叉搜索树的原理相似,只不过这个不一定是二叉)
( 主要理解BTree索引,下面这三种了解即可 )
- Hash索引
- full-text全文索引
- R-Tree索引
(6) 哪些情况需要创建索引
- 主键 自动建立 主键索引(唯一 + 非空)。
- 频繁作为查询条件的字段 应该创建索引。
- 查询中 与其他表关联的字段,外键关系 建立索引。
- 查询中 排序的字段,排序字段若通过索引去访问将大大提高排序速度。
- 查询中 统计 或者 分组 字段(group by也和索引有关)。
(7) 哪些情况不要创建索引
- 记录太少 的表。
- 经常增删改 的表。
- 频繁更新的字段 不适合创建索引。
- Where条件里用不到的字段 不创建索引。
- 数据重复且分布平均的表字段,因此应该只为经常查询和经常排序的数据列建立索引。注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
四、性能分析 (★)
(1) MySQL Query Optimizer
(2) MySQL常见瓶颈
- CPU在饱和 的时候一般发生在数据装入在内存或从磁盘上读取数据时候
- 磁盘I/O瓶颈 :发生在装入数据远大于内存容量时
- 服务器硬件的性能瓶颈:top,free,iostat和vmstat来查看系统的性能状态
(3) Explain 执行计划
介绍
使用 EXPLAIN关键字 可以 模拟优化器执行SQL语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是结构的性能瓶颈
可获取信息
- 表的读取顺序
- 数据读取操作的操作类型
- 哪些索引可以使用
- 哪些索引被实际使用
- 表之间的引用
- 每张表有多少行被优化器查询
语法
Explain+SQL语句
各个字段解释
① id ★
select查询的序列号,包含一组数字,表示 查询中执行select子句或操作表的顺序
可分为三种情况:
- id相同,执行顺序由上至下
(案例中执行顺序为:t1 – t3 – t2)
- id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
(案例中执行顺序为:t3 – t1 – t2)
- id相同不同,同时存在
(案例中执行顺序为:t3 – derived2 – t2 ,derived2 代表从id=2衍生出来的,也就是s1 (虚表))
② select_type
查询的类型,主要用于区别 普通查询、联合查询、子查询等的复杂查询
- SIMPLE:简单的select查询,查询中不包含子查询或者UNION
- PRIMARY:查询中若 包含任何复杂的子部分,最外层查询 则 被标记为PRIMARY
- SUBQUERY:在 SELECT或者WHERE 列表中包含了子查询
- DERIVED:在 FROM 列表中包含的子查询被标记为DERIVED(衍生) MySQL会递归执行这些子查询,把 结果放在临时表 里。
- UNION:若第二个SELECT出现在UNION之后,则被标记为UNION;
若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED - UNION RESULT:从UNION表获取结果的SELECT
③ table
显示这一行的数据是关于哪张表的
④ type ★
显示查询使用了何种类型
从 最好到最差 依次是 ( 常见的类型 ):
system > const > eq_ref > ref > range > index > ALL
一般来说,得保证查询只是达到 range级别,最好达到 ref
- system
表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以 忽略不计
- const
表示 通过索引一次就找到了,const用于比较 primary key或者unique 索引。因为只匹配一行数据,所以很快。如 将主键至于where列表中,MySQL就能将该查询转换为一个常量
- eq_ref
唯一性索引,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描
- ref
非唯一索引扫描,返回匹配某个单独值的所有行。
本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,
它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体
- range
只 检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引
一般就是在你的 where语句中 出现了between、<、>、in等的查询
这种范围扫描索引扫描比全表扫描要好,因为他只需要开始索引的某一点,而结束语另一点,不用扫描全部索引
- index
Full Index Scan,index与ALL区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。
(也就是说虽然all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
- all
FullTable Scan,将遍历全表以找到匹配的行
⑤ possible_keys
显示 可能应用 在 这张表中的索引,一个或多个。
查询涉及的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用
⑥ key ★
实际使用的索引。如果 为 null 则没有使用索引
查询中若使用了覆盖索引,则索引和查询的select字段重叠
⑦ key_len
表示 索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好
key_len显示的值 为索引最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的
⑧ ref
显示索引哪一列被使用了,如果可能的话,是一个常数。那些列或常量被用于查找索引列上的值
⑨ rows
根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数
⑩ Extra ★
包含 不适合在其他列中显示 但十分重要的额外信息
(重点关注前三个打⭐的,其他的了解即可)
- Using filesort ★ (危)
说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
MySQL中无法利用索引完成排序操作成为“文件排序”
- Using temporary ★ (极危)
使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于 排序 order by 和 分组查询 group by
- USING index ★ (喜)
这里是引用表示相应的select操作中使用了覆盖索引(Coveing Index),避免访问了表的数据行,效率不错!
如果同时出现using where,表明 索引被用来执行索引键值的查找;
如果没有同时出现using where,表明 索引用来读取数据 而 非执行查找动作。
- Using where
表明使用了where过滤
- using join buffer
使用了连接缓存
- impossible where
where子句的值总是false,不能用来获取任何元组
- select tables optimized away
在没有GROUPBY子句的情况下,基于索引优化MIN/MAX操作或者
对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,
查询执行计划生成的阶段即完成优化。
- distinct
优化distinct,在找到第一匹配的元组后即停止找同样值的工作
热身Case
五、索引优化 (★)
(1) 索引分析
单表索引分析
此处得出结论:范围之后全失效
两表索引分析
此处得出结论:左连接 建在 右边的表,右连接 建在 左边的表
三表索引分析
JOIN语句的优化
尽可能减少JOIN语句中的NestedLoop(嵌套循环)的总次数:永远都是小的结果集驱动大的结果集。
优先优化NestedLoop的内层循环。
保证JOIN语句中被驱动表上JOIN条件字段已经被索引。
当无法保证被驱动表的JOIN条件字段被索引且内存资源充足的前提下,不要太吝惜Join Buffer 的设置。
(2) 索引失效 (应该避免)
索引失效的的一些案例
① 全值匹配我最爱
全值匹配我最爱
② 最佳左前缀法则 ( 如果索引了多例,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。)
最左前缀要遵守,带头大哥不能s,中间兄弟不能断
③ 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
索引列上少计算
④ 存储引擎不能使用索引中范围条件右边的列
范围之后全失效
⑤ 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select*
覆盖索引不写星
⑥ mysql在使用不等于( != 或者 <>)的时候无法使用索引可能会导致全表扫描
⑦ is null,is not null 也无法使用索引
⑧ like以通配符开头(’%abc…’)mysql索引失效会变成全表扫描操作
LIKE百分写最右
(图片里,type是range,写错了。。。)
问题:解决like’%字符串%'索引不被使用的方法??
- 可以使用主键索引
- 使用覆盖索引,查询字段必须是建立覆盖索引字段
- 当覆盖索引指向的字段是varchar(380)及380以上的字段时,覆盖索引会失效!
⑨ 字符串不加单引号索引失效
VAR引号不可丢
⑩ 少用or,用它连接时会索引失效
6、7、10:不等空值还有or,索引失效要少用
小总结
索引题目练习
Where语句 | 索引是否被使用 |
---|---|
where a = 3 | Y,使用到a |
where a = 3 and b = 5 | Y,使用到a,b |
where a = 3 and b = 5 and c = 4 | Y,使用到a,b,c |
where b = 3 或者 where b = 3 and c = 4 或者 where c = 4 | N,没有用到a字段 |
where a = 3 and c = 5 | 使用到a,但是没有用到c,因为b断了 |
where a = 3 and b > 4 and c = 5 | 使用到a,b,但是没有用到c,因为c在范围之后 |
where a = 3 and b like ‘kk%’ and c = 4 | Y,a,b,c都用到 |
where a = 3 and b like ‘%kk’ and c = 4 | 只用到a |
where a = 3 and b like ‘%kk%’ and c = 4 | 只用到a |
where a = 3 and b like ‘k%kk%’ and c = 4 | Y,a,b,c都用到 |
面试题
复合索引的使用就类似于一个 搭梯子 的过程
(3) 一般性建议
- 对于 单键索引,尽量 选择针对当前query过滤性更好的索引
- 在选择 组合索引 的时候,当前 Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。
- 在选择 组合索引 的时候,尽量选择可以能包含当前query中的where子句中更多字段的索引
- 尽可能通过 分析统计信息 和 调整query的写法 来 达到选择合适索引的目的
个人疑惑总结 — 全值匹配 和 覆盖索引
个人总结,全值匹配 和 覆盖索引 傻傻分不清,经过不断分析,貌似有了一点点理解,记录一下
覆盖索引:就是 select后 的东西都得是 索引中的字段 或者 主键 (因为主键自带主键索引),一旦 select 了 其他字段,索引就会失效,type 变为 all
全值匹配:可以 select 所有字段,但是 必须满足 “带头大哥不能s,中间兄弟不能断”,否则索引就会失效,type 变为 all