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

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

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

9555 次点击
所在节点    MySQL
56 条回复
hosaos
2020-04-13 09:40:10 +08:00
@gz911122 按时间这样是不对的 时间重复的时候无法处理 可以按 id 来
hyd8323268
2020-04-13 10:03:25 +08:00
@hosaos 我用 select id from 表名 where id < [上一页最小 id] order by [时间] desc,id asc limit 10; 这样查的话相反了,越到后面页越快,第一页大概需要 2s 左右,还在想有没有更好的办法呢。
hyd8323268
2020-04-13 10:08:50 +08:00
@jugelizi 如果要支持直接跳转到某页的话,还得保证 id 连续性,才能计算准确起始 id
cloudzhou
2020-04-13 10:09:02 +08:00
select 字段 from 表名 order by 时间戳 desc,id asc limit 0,10;
如果我没有猜错的话,走到了 主键 id 的索引,建立 create index xxx on table (时间戳 desc , id asc)
然后 select 字段 from 表名 (force index xxx)
hyd8323268
2020-04-13 10:13:58 +08:00
@cloudzhou 没走索引
cloudzhou
2020-04-13 10:15:57 +08:00
@hyd8323268 那肯定要走索引啊
b821025551b
2020-04-13 10:21:40 +08:00
@xiaoidea #12
@soseek #13

offset 越大,主键索引访问越频繁,对磁盘 IO 占用越高,这种优化就是干掉频繁的主键索引;
不过 @iffi #10,LZ 所提的是 MyISAM,这种优化只在 InnoDB 下有效。
c4pt0r
2020-04-13 10:24:45 +08:00
其实用 tidb 会好一些...
encro
2020-04-13 10:31:43 +08:00
基本是无解的:
1,count 本来就慢,无解;
2,采用>,<限制查询范围,如果需要精准就无解;
3,采用按时间分区表,也许有用,试试看,估计效果不会很明显,写入性能下降;

所以如果能业务限制采用 2,如果机器资源没有限制采用 3,如果需要实时 count 则需要采用缓存小范围 count
cloudzhou
2020-04-13 10:33:14 +08:00
@c4pt0r 那是屠龙术,千万数据 mysql 还是可以的
Jooooooooo
2020-04-13 10:38:28 +08:00
带条件的大分页是无解问题

只能妥协

有种办法是用 id 作为游标去翻页, 比如现在这一页最大 id 是 A, 那么下一页就是 id>A
barbery
2020-04-13 10:41:16 +08:00
改成走游标就行啦
brader
2020-04-13 10:44:31 +08:00
请问你是执行 select 字段 from 表名 order by 时间戳 desc,id asc limit 0,10; 的时候慢,还是获取表的总行数的时候慢?可以提供你的具体分页需求吗?是只做下一页,还是需要做页码的?
就我所知,千万级,select 字段 from 表名 order by 时间戳 desc,id asc limit 0,10; 的效率还是能接受的
dizun
2020-04-13 10:47:20 +08:00
redis 吧。然后按照楼上说的用程序分。这种级别的用缓存我认为是最优。另外楼上也提到了 io 问题,注意备份数据库。
hyd8323268
2020-04-13 11:00:47 +08:00
@brader 执行第一条 sql 时慢,myisam 是自动记录总条数的。下一页和跳转指定页都要有的。如果不加时间戳排序的话是走索引的,所以快,但是时间戳是有重复的所以走不了索引了。我目前只能考虑用 id 游标来解决,应用层稍微麻烦点。
hyd8323268
2020-04-13 11:09:36 +08:00
@odirus 这种方法的话前几页会查询比较慢,第一页大概需要 2s,页码越大越快。总体来说还可以接受吧。而且,已经根据时间戳排序了,where 中就不需要再加时间戳了吧我觉得。跳转指定页也是个问题 .... 谢谢了
chq3272991
2020-04-13 11:26:40 +08:00
可以尝试下,底层基于日期分区,将大表分区为多个小分区,按日期查询的时候尽量能定位到其中一个分区
iffi
2020-04-13 11:32:38 +08:00
@xiaoidea 看一下 Clustered Indexes 和 Secondary Indexes 的区别就明白了
iffi
2020-04-13 11:35:19 +08:00
@hyd8323268 排序也可以走索引,你需要排序的字段要用到索引覆盖才行。explain 一下,看看 Extra 有没有用到 Using temporary 、Using filesort,最好用到 Using Index
gz911122
2020-04-13 11:46:09 +08:00
@hosaos 可以的,你仔细看一下,重复也无所谓的

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

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

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

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

© 2021 V2EX