LIMIT优化

当我们想要在数据表中查找特定的几行时,常常使用LIMIT关键字限制返回的结果数。但是LIMIT的性能又如何呢?


示例数据表film来自mysql的示例数据库sakila,其中film_id列为主键列(约束),现在我们想查找数据表中第50行以后的5条记录(不包括第50行)


直接使用LIMIT:

LIMIT优化_第1张图片

从结果可以看到,我们返回了film_id从51开始到55结束的5条记录。值得注意的是偏移量50之前有0到49(对应第1行到第50行),因此LIMIT 50,5返回的是第51行到55行

查看执行计划:

LIMIT优化_第2张图片

从执行计划可以看出,我们只是想要特定的5条记录,但是却进行了全表扫描,且没有用到任何索引,无疑多余的磁盘IO很大,时间效率低下。


结合ORDER BY film_id使用(在表中film_id本来就是从小到大排序好,真正目的不是为了排序,而是使用索引):

LIMIT优化_第3张图片

可见返回了相同的记录,下面来看看执行计划:

LIMIT优化_第4张图片

结合ORDER BY使用后只检索了55行,且使用到了主键索引进行匹配。为什么会只检索55行呢?唯一的解释只有:引擎先对film_id列的索引进行从小到大排序并限定了偏移量与索引节点的数量(偏移的节点也要算入其中,共要选定55个,还没智能到直接找到特定的那5个节点)。再根据选定的索引节点(第1个到第55个)指向数据库表中相应的行进行匹配。运用这种方式不会进行全表扫描,磁盘IO低,且时间效率也会比直接LIMIT的方式高。


但是这种方法也有弊端,例如当偏移量很大时,引擎对film_id列的索引进行排序与限制数量确定的索引节点数量也会很大。这样在数据表中匹配的行数就会很多,相当于全表扫描,而且还付出了排序很多索引(从小到大)的沉重代价,还不如直接LIMIT

LIMIT优化_第5张图片


比较好的办法就是限定film_id的范围进行查找:

LIMIT优化_第6张图片

  1. 从执行计划看,这种SQL查询使用了索引匹配行数(先查找索引找到满足条件的只有5个,再指向数据表进行匹配。不用索引就会进行全盘扫描),磁盘IO就是想要的结果。
  2. 但这种查询要求事先已得到索引列的序号。

你可能感兴趣的:(MySQL性能优化)