目录
准备阶段:
SQL性能下降的原因:
SQL的执行顺序
多表联查
索引
索引分类
为啥用索引b树查询和b树的优势
哪些情况需要创建索引
那些情况不要创建索引?
MySQL常见瓶颈:
Explain命令(索引调优必备基础)
id
select_type
table
type
possible_keys
key_len
Ref
rows
Ertx(补充说明)
索引优化:小案例
索引失效:
索引一般性建议:
优化总结口诀
一般优化流程分析:
查询优化
Order by 优化
什么情况下单路不如双路
Order by满足两情况,会使用Index方式排序
Order by什么情况,不能使用索引进行排序:
Gourp by
慢查询日志浅谈
原来写的有兴趣可以看看
查询语句写的烂
索引失效
关联查询太多join(设计缺陷或不得已的需求)
服务器调优及各个参数设置(缓冲、线程数等)
form -> on -> (left right)join -> group by ->having -> select ->distinct ->order by ->limit
(39条消息) SQL执行顺序_✘迟暮的博客-CSDN博客
left join 显示左边的全部 =共有数据加上左表独有的的数据
right join 显示右表的全部数据 =共有数据加上右表独有的数据
Inner join 显示两个表公共的数据
select <> from table a left join table b on a.key =b.key where b.key is null 显示左表独有的数据
相反right join 显示右表独有的数据
outer join 显示俩个表的所有数据
select <> from table a full outer join table b on a.key =b.key where b.key is null or a.key is null 显示左右表的独有数据,不显示其中的共有数据
索引是帮助MySQL高效获取数据的数据结构。可以得到索引的本质:索引就是数据结构。
索引就是排好序的快速查找 的数据结构。
单值索引:即一个索引只包含单个列,一个表可以有多个单列索引
唯一索引:索引列的值必须唯一,但允许有空值
复合索引
总计三次磁盘I/O 第一次 先把磁盘块1由磁盘加载到内存 大范围 先锁定指针所在的磁盘块,第二次锁定磁块盘数据的所在区域 缩减范围,第三次找到最后的一块范围同时通过二分查找找到,所需的值
3层b+树可以表示上百万的数据,只需3次I/O,性能提升是巨大的,如果没有索引,每项数据都要发生一次I/O,南无总共就需要百万次IO,成本极高。
CPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候
IO:磁盘I/O瓶颈发生在装入数据远大于内存容量的时候
服务器硬件的性能瓶颈:top、free、iostat和vmstat来查看系统的性能状态
+----+-------------+---------+------+---------------+------+---------+------+------+-------
+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------
+ | 1 | SIMPLE | servers | ALL | NULL | NULL | NULL | NULL | 1 | NULL |
+----+-------------+---------+------+---------------+------+---------+------+------+-------
id 是用来顺序标识整个查询中 SELELCT 语句的,在嵌套查询中 id 越大的语句越先执行。该值可能为 NULL,如果这一行用来说明的是其他行的联合结果。
表示查询的类型
对应行正在访问哪一个表,表名或者别名
注意:MySQL 对待这些表和普通表一样,但是这些“临时表”是没有任何索引的。
type 显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL ,一般来说,得保证查询至少达到 range 级别,最好能达到 ref。
记下边几个比较常用的也可以 Type 访问类型排序 从最好到最差依次是:
System>const>eq_ref>ref>range>index>ALL
显示查询使用了哪些索引,表示该索引可以进行高效地查找,但是列出来的索引对于后续优化过程可能是没有用的
KEY
实际使用的索引。如果为NULL,则没有使用索引
查询中若使用了覆盖索引,则该索引仅出现在key列表中
key_len 列显示 MySQL 决定使用的键长度。如果键是 NULL,则长度为 NULL。使用的索引的长度。在不损失精确性的情况下,长度越短越好 。
显示索引的哪一列被使用了。如果可能的话,是一个常数。那些列或常量被使用于查找索引列上的值
rows 列显示 MySQL 认为它执行查询时必须检查的行数。注意这是一个预估值。
Using filesort : 说明MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。 MySQL中无法利用索引完成的排序操作称为“文件排序”。
Using temporary :使用了临时表保存中间结果。MySQL在对查询结果排序时使用临时表。常见于排序order by 和分组 group by。 拖慢你的sql
注意 : 要建索引在排序的时候一定要使用,要不会产出临时表,要不就进行排序,要不就别建索引
Using index:表示相应的select操作中使用了覆盖索引,避免访问表的数据行,效率不错!如果同时出现using where,表明索引被使用来执行索引键值的查找; 如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。 覆盖索引(查询列要被所建的索引覆盖 或可以说 一个索引包含了(或覆盖了)满足查询结果的数据就也叫覆盖索引)
注意:如果要遇到覆盖索引,一定要注意select列表中只取出需要的列,不可select*
因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降
Using join buffer :使用了连接缓存
Impossible where :where子句的值总是false,不能用来获取任何元组(例如:explan select * from staffs where name=’july’ and name=’z3’; 你输的这个叫july又叫z3让MySQL错乱了)
Selecet tables optimized away: 在没有groupby字句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段在进行计算,查询执行计划生成的阶段即完成优化。
Distinct:优化distinct操作,在找到第一次匹配的元组后即停止找同样值的动作。
范围以后的索引会失效,效率低 例如索引(sex_name_views) 在 where sex =1 and name>1 order by views 中name后的索引用查询效率低
EXPLAIN selecet id ,author_id from ‘article’ where category_id =1 and comments>1 order by views desc limit 1;
EXPLAIN selecet id ,author_id from ‘article’ where category_id =1 and comments=1 order by views desc limit 1;
结论:
Type变成了range这个是可以忍受的。但是extra 里使用Using filesort仍是无法接受的。
但是我们已经建立了索引,为啥没用呢》
这里因为按照BTree索引的工作原理。
先排序category_id.
如果遇到相同的category_id则再排序comments,如果遇到相同的comment则再排序views。当comments字段在联合索引力处于中间位置时
因comments>1条件是一个范围值(所谓range)
MySQL无法利用索引再对后面的views部分进行检索,即range类型查询字段后面的索引无效
EXPLAN select * from class left join book on class.card =book.card
结论:type有ALL
分别左右表都添加索引,第二行的type变为了ref,rows也变成小了,优化比较明显
这是有左连接的特性决定的,left join 条件用于确定如何从右表搜索行,左表一定都有。
所以左连接索引一定要加右表。
总结
Optimizer 优化器自我优化分析会根据索引的进行自我调整where语句的顺序。
group by 分组并排序
定值、范围还是排序,一般order by是给个范围
Group by 基本上都需要进行排序,会有临时表产生
全值匹配我最爱,最左前缀要遵守。
带头大哥不能死,中间兄弟不能断。
索引列上少计算,范围之后全失效。
LIKE百分写最右,覆盖索引不写星。
不等空值还有or,索引失效要少用。
VARCHAR引号不可丢,SQL高级也不难。
总结
永远小表驱动大表,即小的数据集驱动大的数据集。
原理(RBO)
Select * from A where id in (select id from B);
当B表的数据集必须小于A表的数据集时,用in优于exists。
当A表的数据集系小于B表的数据集时,用exists优于in。
EXISTS(用途解释)
Select from table where exists(subquery)
该语法可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果(True 或 false)来决定主查询的结果是否得以保留。
提示:
- exists(subquery)只返回true或false,因此子查询中的select * 也可以时select 1 或select ’x‘,官方说法时实际执行时会忽略Select清单,因此没有区别。
- Exists子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比,如果担忧效率问题,可进行实际检验以确定是否有效率问题。
- Exists 子查询往往也可以用条件表达式、其子查询或者JOIN来替代,何种最优需要具体问题具体分析
Order by子句,尽量使用index方式排序,避免使用filesort凡是排序
尽可能在索引列上完成排序操作,遵照索引建的最左前缀
如果不能在索引列上,filesort有两种算法;
Mysql就要启动双倍排序和单路排序
优化策略:增大sort_buffer_size参数的设置
增大max_length_for_sort_data参数的设置
名词解释
双路算法:
取一批数据,要对磁盘进行了两次扫描。
单路排序:
从磁盘读取查询需要的所有列,按照order by列在buffer对它们进行排序,然后扫描排序后的列表进行输出,它的效率更快一些,避免了第二次读取数据。并且把随机io变成了顺序io,但是它会使用更多的空间,因为它把每一行都保存在内存中。
什么情况下单路不如双路
在sort_buffer中,方法B比方法A要多占用更多空间,因为方法B时把所有字段都取出,所以有可能取出的数据的总大小超过了sort_buffer的容量,导致每次只能取sort_buffer容量大小的数据,进行排序(创建tmp文件,多路合并),排完在取取sort_buffer容量大小,再排。。。。从而多次i/o
1.Order by语句使用索引最左前列
2.使用where子句与order by字句条件列组合满足索引最左前列
3.如果WHERE使用索引的最左前缀为常量,则order by能使用索引
1.排序不一致
2.丢失最左索引和中间索引
3.字段不是索引的一部分
4.a in(...)order by b,c对于排序来说,多个相等条件也是范围查询,
Gourp by比order by就多个having,能在where中使用的尽量不要使用having
索引 着重排序和查找
慢查询,具体指运行时间超过long_query_time值的sql,则会被记录到慢查询日志中
long_query_time默认10秒
(39条消息) SQL优化_✘迟暮的博客-CSDN博客
(39条消息) MySQL_✘迟暮的博客-CSDN博客
(39条消息) MySQL索引_✘迟暮的博客-CSDN博客_mysql创建位图索引