MySQL索引优化

分页查询优化

SELECT * FROM employees limit 10000, 10;

表示从employees表10001行开始的取10条记录。执行这条SQL是先读取10010条记录,然后抛弃前10000条,然后读到后面10条想要的数据。

1. 根据自增且连续的主键排序的分页查询

SELECT * FROM employees limit 90000, 5;(没添加单独order by,表示通过主键排序)

SELECT * FROM employees where id > 90000 limit 5; (按照主键去查询从第90001开始的5行数据)

 必须满足:

        1. 主键自增且连续;

        2. 结果是按照主键排序的;

2. 根据非主键字段排序的分页查询

SELECT * FROM employees ORDER BY name limit 90000, 5;

并未使用name字段的索引:扫描整个索引并查找到没索引的行的成本比扫描全表的成本更高,所以优化器放弃使用索引。

优化:让排序时返回的字段尽可能的少,所以可以让排序和分页操作先查出主键,然后根据主键查到对应的记录  

SELECT * FROM employees e INNER JOIN (SELECT id FROM employees ORDER BY name limit 90000, 5) ed ON e.id = ed.id;

原SQL使用的是filesort排序,而优化后的SQL使用的是索引排序。

Join关联优化查询

MySQL的表关联常见算法

        Nested-Loop Join算法

        Block Nested-Loop Join算法

1. 嵌套循环连接(NLJ)算法

        一次一行循环地从第一张表(驱动表)中读取行,在这行数据中取到关联字段,根据关联字段在另一张表(被驱动表)里取出满足条件的行,然后取出两张表的结果合集。

        SELECT * FROM t1 INNER JOIN t2 on t1.a=t2.a;

         驱动表是t2,被驱动表是t1.MySQL会优先选择小表(数据量较小)做驱动表,所以驱动、非驱动和SQL排列无关;

        left join时,左表是驱动表,右表是非驱动表,当使用right join时,右表是驱动表,左表是被驱动表,简单的join时,mysql会选择数据量比较小的表作为驱动表,大表作为被驱动表;

        一般join语句中,如果执行计划Extra中未出现Using join buffer则表示使用join算法是NLJ

执行流程:

        1. 从t2中读取一行数据(如果有过滤条件,则会从过滤结果中取出一行数据)

        2. 从第1步的数据中,取出关联字段a,到t1中查找;

        3. 取出t1中满足条件的行,跟t2中获取到的结果合并,作为结果返回给客户端;

        4. 重复1-3

整个过程会读取t2表的所有数据,然后根据t2.a行的值索引扫描t1表中的对应行。一共扫描200行。

2. 基于块的嵌套循环连接算法(BNL)

把驱动表的数据读入join_buffer中,然后扫描被驱动表,把被驱动表每一行取出来跟join_buffer中的数据做对比。

         1. 把t2的所有数据放入join_buffer中;

         2.把表t1中每一行取出来,跟join_buffer中的数据作对比;

          3.返回满足join条件的数据 

整个过程对表t1和t2进行一个全表扫描,因此扫描的总行数为10000(t1)+100(t2),并且join_buffer中的数据是无序的,所以内存中判断次数为100*10000=100万次。

对于被驱动表的关联字段没索引的关联查询,一般都会使用BNL算法。如果有索引一般选择NLJ算法,有索引的情况下NLJ算法比BNL算法性能更高。

对于关联SQL的优化

        关联字段加索引:尽量使用NLJ算法;

        小表驱动大表:在SQL进行多表连接时,如果明确知道哪张表是小表,可以直接使用straight_join,省去mysql优化器自己判断的时间;straight_join只适用于inner_join,并不适用于left, right_join

IN和EXISTS优化

        小表驱动达标:小的数据集驱动大的数据集。

in:当B表的数据集小于A表的数据集时,in优于exists:select * from A where id in (select id from B)

exists:当A表的数据集小于B 的数据集时,exists优于in

        1. EXISTS只返回TRUE和FALSE,因此子查询中的SELECT * 也可以用SELECT 1替换

        2. EXISTS子查询的实际执行火车可能经过了优化而不是我们理解的逐条对比;

        3. EXISTS子查询往往也可以用JOIN来代替

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值