大数据下的分页:
limit 及翻页优化,limit offset,N, 当offset非常大时, 效率极低,
原因是mysql并不是跳过offset行,然后单取N行,
而是取offset+N行(跳过100万行,就是返回100万行,然后返回n行,再把其他的行扔掉)
效率较低,当offset越大时,效率越低
mysql>
select
*
from
emp limit 1000000,3;
+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+
| 1100002 | JItXJo | SALESMAN | 1 | 2018-01-05 | 2000.00 | 400.00 | 266 |
| 1100003 | LdkQxP | SALESMAN | 1 | 2018-01-05 | 2000.00 | 400.00 | 347 |
| 1100004 | YOcUrZ | SALESMAN | 1 | 2018-01-05 | 2000.00 | 400.00 | 460 |
+
3
rows
in
set
(0.48 sec)
mysql>
select
*
from
emp limit 3000000,3;
+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+
| 3100002 | HsQcNK | SALESMAN | 1 | 2018-01-05 | 2000.00 | 400.00 | 106 |
| 3100003 | TOpgMq | SALESMAN | 1 | 2018-01-05 | 2000.00 | 400.00 | 202 |
| 3100004 | XHtWAN | SALESMAN | 1 | 2018-01-05 | 2000.00 | 400.00 | 143 |
+
3
rows
in
set
(1.11 sec)
当跳过数量过多时,时间就长了。
优化办法:
1: 从业务上去解决
办法: 不允许翻过100页
以百度为例,一般翻页到70页左右.
1:不用offset,用条件查询.
例:
mysql>
select
id,
name
from
lx_com limit 5000000,10;
+
| id |
name
|
+
| 5554609 | 温泉县人民政府供暖中心 |
..................
| 5554618 | 温泉县邮政鸿盛公司 |
+
10
rows
in
set
(5.33 sec)
mysql>
select
id,
name
from
lx_com
where
id>5000000 limit 10;
+
| id |
name
|
+
| 5000001 | 南宁市嘉氏百货有限责任公司 |
.................
| 5000002 | 南宁市友达电线电缆有限公司 |
+
10
rows
in
set
(0.00 sec)
这种方式要求数据没有删过,id是连续的。
问题: 2次的结果不一致
原因: 数据被物理删除过,有空洞.
解决: 数据不进行物理删除(可以逻辑删除).
(一般来说,大网站的数据都是不物理删除的,只做逻辑删除,逻辑标记 ,比如 is_delete=1)
3: 非要物理删除,还非要用offset精确查询,还不能限制用户分页,用户可以直接跳到100万页,怎么办? 延迟关联。
分析: 优化思路是 不查,少查,查索引,少取.
我们现在必须要查,则只查索引,不查数据,得到id,id索引再内存里面, 再用id去查具体条目. 这种技巧就是延迟索引.
mysql>
select
id,
name
from
lx_com
inner
join
(
select
id
from
lx_com limit 5000000,10)
as
tmp using(id);
之前的
select
*
from
emp limit 5000000,10;是在索引数上找了500万行并且回行了500万次来找
name
,因此回行到硬盘找了500万次。
select
id,
name
from
lx_com
inner
join
(
select
id
from
lx_com limit 5000000,10)
as
tmp using(id);这个是先再索引树上找到10行,然后回行10次到硬盘就可以了。