112 lines
3.7 KiB
Markdown
112 lines
3.7 KiB
Markdown
---
|
||
page-title: "一张数据量很大的表,SQL分页查询特别耗时,你有什么优化方案? - 董川民"
|
||
url: https://www.dongchuanmin.com/mysql/2101.html
|
||
date: "2023-09-06 17:43:56"
|
||
---
|
||
像标题那样的问题,你一般都是如何去做查询呢?下面来看看,实际开发中我们会遇到,面试的时候也是会被问到的问题。
|
||
|
||
在开发过程中我们经常会使用分页,核心技术是使用limit进行数据的读取,在使用limit进行分页的测试过程中,得到以下数据:.
|
||
|
||
```
|
||
select * from news order by id desc limit 0,10
|
||
耗时0.003秒
|
||
select * from news order by id desc limit 10000,10
|
||
耗时0.058秒
|
||
select * from news order by id desc limit 100000,10
|
||
耗时0.575秒
|
||
select * from news order by id desc limit 1000000,10
|
||
耗时7.28秒
|
||
```
|
||
|
||
我们惊讶的发现mysql在数据量大的情况下分页起点越大查询速度越慢,100万条起的查询速度已经需要7秒钟。这是一个我们无法接受的数值!
|
||
|
||
**改进方案 1**
|
||
|
||
```
|
||
select * from news
|
||
where id > (select id from news order by id desc limit 1000000, 1)
|
||
order by id desc
|
||
limit 0,10
|
||
```
|
||
|
||
查询时间 0.365秒,提升效率是非常明显的!!原理是什么呢???
|
||
|
||
我们使用条件对id进行了筛选,在子查询 (select id from news order by id desc limit 1000000, 1) 中我们只查询了id这一个字段比起select \* 或 select 多个字段 节省了大量的查询开销!
|
||
|
||
**改进方案2**
|
||
|
||
适合id连续的系统,速度极快!
|
||
|
||
```
|
||
select * from news
|
||
where id between 1000000 and 1000010
|
||
order by id desc
|
||
```
|
||
|
||
不适合带有条件的、id不连续的查询。速度非常快!
|
||
|
||
**百万数据分页的注意事项**
|
||
|
||
接上一节,我们加上查询条件:
|
||
|
||
```
|
||
select id from news
|
||
where cate = 1
|
||
order by id desc
|
||
limit 500000 ,10
|
||
```
|
||
|
||
查询时间 20 秒
|
||
|
||
好恐怖的速度!!利用上面方案进行优化:
|
||
|
||
```
|
||
select * from news
|
||
where cate = 1 and id > (select id from news where cate = 1 order by id desc limit 500000,1 )
|
||
order by id desc
|
||
limit 0,10
|
||
```
|
||
|
||
查询时间 15 秒
|
||
|
||
优化效果不明显,条件带来的影响还是很大!在这样的情况下无论我们怎么去优化sql语句就无法解决运行效率问题。
|
||
|
||
那么换个思路:建立一个索引表,只记录文章的id、分类信息,我们将文章内容这个大字段分割出去。
|
||
|
||
表 news2 \[ 文章表 引擎 myisam 字符集 utf-8 \]
|
||
|
||
\-------------------------------------------------
|
||
|
||
id int 11 主键自动增加
|
||
|
||
cate int 11 索引
|
||
|
||
在写入数据时将2张表同步,查询是则可以使用news2 来进行条件查询:
|
||
|
||
```
|
||
select * from news
|
||
where cate = 1 and id > (select id from news2 where cate = 1 order by id desc limit 500000,1 )
|
||
order by id desc
|
||
limit 0,10
|
||
```
|
||
|
||
注意条件 id > 后面使用了news2 这张表!
|
||
|
||
运行时间 1.23秒,我们可以看到运行时间缩减了近20倍!!数据在10万左右是查询时间可以保持在0.5秒左右,是一个逐步接近我们能够容忍的值!
|
||
|
||
但是1秒对于服务器来说依然是一个不能接受的值!!还有什么可以优化的办法吗??
|
||
|
||
我们尝试了一个伟大的变化:
|
||
|
||
将 news2 的存储引擎改变为innodb,执行结果是惊人的!
|
||
|
||
```
|
||
select * from news
|
||
where cate = 1 and id > (select id from news2 where cate = 1 order by id desc limit 500000,1 )
|
||
order by id desc
|
||
limit 0,10
|
||
```
|
||
|
||
只需要 0.2秒,非常棒的速度。
|
||
|
||
到了这一步,我们的分页优化完毕,显然是有很大的效果的。你自己可以测试一下! |