从 MySQL 的 LIMIT 聊起
一次 SQL 查询优化原理分析:900W+ 数据,从 17s 到 300ms
数据量
mysql> select count(*) from test;
+----------+
| count(*) |
+----------+
| 5242882 |
+----------+
1 row in set (4.25 sec)
表格式
mysql> desc test;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| val | int(10) unsigned | NO | MUL | 0 | |
| source | int(10) unsigned | NO | | 0 | |
+--------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
id 为自增主键,val 为非唯一索引。
给出一个使用 limit 的查询 SQL
mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id | val | source |
+---------+-----+--------+
| 3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
5 rows in set (15.98 sec)
如上可以看到花费了 15s, 为什么这么慢?
问题一:LIMIT 执行逻辑
-
执行逻辑
比如当我们用 limit 1000000, 10 的时候,MySQL 会先扫描满足条件的 1000010 行,扔掉前面的 1000000 行,返回后面的 10 行。所以 offset 越大的时候,扫描的行就越多,效率也就越慢了。
-
为什么这么执行?
大家都知道,MySQL内部其实是分为server层和存储引擎层的: 扩展一:MySQL 的架构
MySQL是在server层准备向客户端发送记录的时候才会去处理LIMIT子句中的内容。 扩展二:MySQL 语句的执行顺序