mysql 近千万级数据表,在分页时有什么好的方案吗。

2020-04-12 20:53:21 +08:00
 hyd8323268

单表 800w 条,myisam 引擎。 需要根据一个值为时间戳的字段进行排序,时间戳有重复值,普通索引。 刚开始是采用的:select 字段 from 表名 order by 时间戳 desc,id asc limit 0,10; 但是特别慢,前几页还好,越到后面越慢。 百度了几个方案试了都感觉没什么特别大的变化。

9818 次点击
所在节点    MySQL
56 条回复
iffi
2020-04-13 11:46:27 +08:00
@#27 楼 确实,在 MyISAM 下,优化不明显。看看能不能在业务层面优化,优化思路无非就是不查、少查、走索引、少取
lasuar
2020-04-13 14:22:35 +08:00
通过子查询优化
select * from table where id>=(select id from table limit 10000,1) limit 100
另外大表慎用 select *,一般都查询指定字段,把这些经常查询的字段和 where 的条件字段建立复合索引,避免回表,就最大化利用索引了。
hyd8323268
2020-04-13 15:45:35 +08:00
@lasuar 重点是排序,我知道这些的
brader
2020-04-13 15:50:23 +08:00
@hyd8323268 如果你需求一定要时间排序的话,我觉得你可以试试,给时间戳建立索引,然后使用微秒级时间戳,看下这样能不能避免时间戳太多重复的情况?这个就要看你业务了
laoba
2020-04-13 16:09:01 +08:00
select * from articles where id between (select id from articles limit 170000,1) and (select id from articles limit 170500,1)
感觉还是这个靠谱
xiaochun41
2020-04-13 16:26:44 +08:00
单从技术上讲,可能没有太好的解决方案。
根据我个人的经验看,可以从业务的角度做一些优化或者妥协。
比如:真的需要一页一页翻么?
weiqk
2020-04-13 17:34:03 +08:00
不要脱离业务谈技术,结合实际业务才有解决办法,是什么类型的数据?日志还是财务数据
hosaos
2020-04-13 19:44:49 +08:00
@gz911122 假设数据如下,分页 pageSize 也是 1,不针对 id,只针对时间是查不出 id 为 2 的数据的,第二页的条件不是 time<2019-07-12 15:14:42 limit 1?
id time
1 2019-07-12 15:14:42
2 2019-07-12 15:14:42
3 2019-07-12 15:14:42
hyd8323268
2020-04-13 20:27:48 +08:00
@weiqk 日志类的,访问记录,也就在后台看看,目前没有删除功能。
weiqk
2020-04-14 05:04:38 +08:00
@hyd8323268 上 es
gz911122
2020-04-14 09:53:12 +08:00
@hosaos id 也要带上的,你看下我回复的#4 楼
qyvlik
2020-04-14 09:58:53 +08:00
先为表建好时间戳的索引,时间戳字段是否唯一,关系不大。只要不是说 800w 记录,时间戳的取值集合就百来个,这个时间戳就有建立索引的价值。

1. 摈弃传统的精确分页,直接走瀑布流加载方案
- 取第一页:select * from logs order by create_time desc limit 10
- 可以在前端将 min(create_time) 取出,作为第二第三页的查询条件
- select * from logs where create_time < pre_min_time order by create_time desc limit 10

2. 仍然想使用精确分页
1. 使用时间区间将要扫描的条数减少,例如 一天的日志数量
2. 使用一些 sql 查询进行优化,例如 max, min 查找出对应的时间范围、id 范围

3. 使用其他的查询方案,例如 es 、mongo 、redis

ps: 如果一些索引效果不明显,考虑将 myisam 表数据导入新的 InnoDB 的表,在 InnoDB 表上建立索引。
neverxian
2020-04-14 11:10:20 +08:00
看一看
hosaos
2020-04-15 09:18:58 +08:00
@gz911122 id 带上就没问题了 但是这种时候 带上时间条件是多余的把 带 id 必须按 id 排序 否则按时间排序 id 不连续 没有意义
gz911122
2020-04-15 10:12:31 +08:00
@hosaos 不多余,先时间排序再 id 排序, 有意义的. 是为了避免重复问题.
tmackan
2021-06-17 20:25:35 +08:00
比如要导出全部账单的话
1.传统分页的话,offset 可以算出来,这样可以精确分页,但是 offset 越大越慢,调用方第一次拿到 total 总数后,可以并发的请求后续分页数据
2.游标的方式的话,利用 select * from table where id < cursor order by time desc limit 1000
调用方通过串行的方式,每次用前一页的最小 ID 来作为下一页的 cursor
优点是可以保证数据不重复,缺点是无法并行请求,只能串行每次获取游标

折中的做法
调用方自己计算 cursor 并且并行的请求,后台还是通过游标的方式处理
但是数据重复的问题,需要调用方 去重

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/661755

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX