欢迎光临
我们一直在努力

MySQL索引优化练习

Explain

有时候position_keys有值,key为空,被优化之后没有走索引,可以使用force index(index_name)来强制走索引

–强制走索引

explain select * from employees force index(idx_name_age_position) where name > 'LiLei' and age = 22 and position = 'manager';

走没走索引,有时候和数据量和查询条件有关系。查询时的cost决定了是否会使用索引。


索引下推:

以下两种都支持下推,但 LIKE前缀匹配(如 'LiLei%')在复合索引场景下收益最大(一般情况下大于条件的结果集范围更大,而like 'LiLei%'的结果集相对更小)。

–前提:name,age,position为组合索引 –不走索引,我的理解是范围太大,所以没使用索引下推,而不是因为name > 'LiLei'
explain select * from employees where name > 'LiLei' and age = 22 and position = 'manager';
–走索引
explain select * from employees where name like 'LiLei%' and age = 22 and position = 'manager';

为什么下面的走索引?

使用了索引下推(ICP-Index Condition Pushdown,5.6开始引入,把过滤工作提前,Extra列显示Using index condition,说明ICP生效):

定义:索引下推(Index Condition Pushdown, ICP)​ 是 MySQL 5.6 引入的一项查询优化技术。它的核心机制是将 WHERE 子句中的过滤条件“下推”到存储引擎层执行,从而在扫描索引时提前过滤掉不符合条件的记录,减少回表次数,提升查询效率。

MySQL 5.6+ 默认开启。可通过 SET optimizer_switch = 'index_condition_pushdown=on/off';手动控制,不推荐关闭。

5.6之前,先查询出name like 'LiLei%'的数据,然后去聚簇索引中查出数据,返回MySQL服务器层(Server层),在此结果集基础上再进行age = 22 and position = 'manager'的比较。

5.6之后,在存储引擎层在扫描索引时,直接应用 WHERE 条件中涉及索引列的过滤条件,查询出name like 'LiLei%' and age = 22 and position = 'manager'的数据返回给Server层,再去聚簇索引中查询结果,回表次数更少。

trace工具:

–一起执行,查看MySQL优化细节
explain select * from employees where name > 'a' order by position;
select * from infomation_schema.OPTIMIZER_TRACE;


order by&group by优化

MySQL支持两种排序方式filesortindexindex效率高,filesort效率低。

index

        Extra列中的Using index是指MySQL扫描索引本身完成排序,在存储引擎层完成排序。

order by满足两种情况会使用Using index

组合索引 index_com(name,age,position)

1.order by语句使用索引最左前列。 — order by name, age; order by name; order by name,age, position;

2.使用where子句与order by子句条件列组合满足索引最左前列。– where name = 'a' order by age; where name = 'a' order by age,position;

尽量在索引列上完成排序,遵循索引建立(索引创建的顺序)时的最左前缀法则。

filesort

        如果order by的条件不在索引列上,就会产生Using filesort(和Using index是互斥的),这种情况说明没有在存储引擎上完成排序,需要由MySQL服务器层在内存或者磁盘上完成排序。数据量小于sort_buffer_size时,在内存中完成排序,未使用外部排序;数据量超过sort_buffer_size时,MySQL会将数据分块排序后写入临时磁盘文件(外部的来源),再通过多路归并算法合并,此时才涉及外部排序。

能用覆盖索引尽量使用覆盖索引。

group by与order by很类似,其实质是先排序后分组,遵照索引创建顺序的最左前缀法则。对于group by的优化如果不需要排序的可以加上order by null禁止排序。注意,where高于having(能不使用having就不要用),能写在where中的限定条件就不要去having限定了。


Using filesort文件排序原理详解

排序方式:

        单路排序:一次性取出满足条件的所有字段,在sort buffer(占用空间大,内存压力小,默认1M大小)中进行排序,顺序度,一次性读取数据,效率高。触发:查询列总长度或者

三个步骤:

根据查询条件,将所有需要返回的字段(包括排序字段和查询字段)一条条读取放入 sort_buffer内存区域。(为什么不是一次性读取放入sort_buffer中?数据量太大,容易导致内存溢出)

在 sort_buffer中直接对数据按照 ORDER BY指定的字段进行排序。

排序完成后,直接将 sort_buffer中的有序数据返回给客户端,无需再次访问原表。

        双路排序:又叫回表排序模式。首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行ID,然后在sort buffer(占用空间小,内存压力小)中进行排序,排序完后需要再次取回其他需要的字段。随机读,排序后回表去数据是随机IO,性能损耗大。触发:查询列总长度>max_length_for_sort_data阈值。用trace工具可以看到sort_mode信息显示。

两者都是扫描聚簇索引。Using index才是扫描二级索引。

原因:

内存限制与不确定性:每个连接线程专用的sort_buffer大小是固定的,在开始读取数据时,无法预知最终会命中多少条符合条件的数据。如果数据量远超sort_buffer容量,一次性加载的尝试会直接导致内存溢出。

流水线操作:数据库的查询执行引擎是一个流水线过程。存储引擎层在根据索引或全表扫描定位到一条数据后,可以立即将其交给上层的排序逻辑进行处理。这种“来一条处理一条”的流式处理模式,无需等待所有数据准备完毕,可以更早地开始排序准备工作。


设计索引原则:

        代码先上,索引后上

        联合索引尽量覆盖条件,比如联合索引为proxince,city,sex,age字段,age字段一般是范围查询,age就最好放后面,如果中间有个字段(sex)不在查询条件中,可以使用 sex in ('femali',mali'),适用值少的字段,让age能延续上联合索引的前两个字段province和city。可以建多个联合索引,具体情况再分析。

        不要在小基数字段上建立索引

        长字符串我们可以采用前缀索引

        CREATE INDEX idx_email_prefix ON users (email(5));

                优点:

                        长字符串字段,能减少索引体积

                        前缀匹配查询,like 'abc%',能有效利用索引

                        BLOB/TEXT 类型字段只能建立前缀索引

                局限性:

                        无法用于排序/分组

                        无法实现覆盖索引

                        非前缀匹配无效

        where与order by冲突时优先选择where

        基于慢sql查询做索引优化

赞(0)
未经允许不得转载:171主机测评 » MySQL索引优化练习
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址