MYSQL 评论表结构优化

2018-05-02 16:40:04 +08:00
 Aluhao

数据表结构

CREATE TABLE comments (

id bigint(20) unsigned NOT NULL AUTO_INCREMENT,

aid bigint(20) unsigned NOT NULL DEFAULT '0',

uid bigint(20) unsigned NOT NULL DEFAULT '0',

contents text NOT NULL,

likes int(10) unsigned NOT NULL DEFAULT '0',

comments int(10) unsigned NOT NULL DEFAULT '0',

time int(10) unsigned NOT NULL DEFAULT '0',

PRIMARY KEY (id),

KEY aid (aid),

KEY time (time)

) ENGINE=MyISAM DEFAULT CHARSET=utf8;

现在有 7 千万数据, 表大小 3.60 GB 索引大小 2.55 GB ; AID 是新闻的 ID ; UID 是评论用户; contents 是评论内容; 随着数据越来越多表越来越大,如果分表,业务逻辑很麻烦,又达不到需求,有什么好的优化方案?

我现在想把 contents 内容单独一个表存放,就是说这个评论表 增加一个表;

CREATE TABLE comments_data (

id bigint(20) unsigned NOT NULL DEFAULT '0',

contents text NOT NULL,

PRIMARY KEY (id)

) ENGINE=MyISAM DEFAULT CHARSET=utf8;

这样虽然能优化一些,但终究不是最终解决方案,不知道 V2 朋友们有没做过类似的数据结构优化;

7394 次点击
所在节点    MySQL
44 条回复
breadenglish
2018-05-02 17:17:12 +08:00
mongoDB 了解一下
aliipay
2018-05-02 17:19:44 +08:00
业务逻辑很麻烦---具体有哪些?
monsterxx03
2018-05-02 17:23:00 +08:00
你现在瓶颈在哪, 查询速度太慢还是怎么的, 看看 MySQL 自己的 partition 功能满不满足你需求, 那样不用动业务代码.

老能看到动不动给人推荐 MongoDB, ElasticSearch 的, 连人家问题都不了解一下,也是醉了
aliipay
2018-05-02 17:23:30 +08:00
简单猜测一下,有根据 aid 查询和根据时间范围查询,
可以设计一个 key,由 time+id 组成,如 2018050200000123,用来代替现有的 aid 和 time。然后根据新的 key 进行分表,应该是满足上面 2 个查询需求。
Aluhao
2018-05-02 17:28:37 +08:00
@aliipay aid 是新闻 ID,就是每打开新闻,都得用这个 ID 去查询用户的评论,还要翻页等,所以如果按日期存放,数量查出来估计是全部,要做成分页估计麻烦些;
breadenglish
2018-05-02 17:28:45 +08:00
@monsterxx03 兄弟你理解能力没问题吧,人家的问题很明确了,你要不要再仔细看看。
xiaoban
2018-05-02 17:28:59 +08:00
如果单用数据库可以按照新闻 id 分表,这样可能会造成数据分布不均匀。

新闻评论的业务类型,如果插入数据后大多不会修改只是查询,可以使用数据库做持久数据,使用 es 这种专门做查询的搜索服务,插入数据库后就可以往 es 抛,同一个机房抛送基本等于实时。
由于查询不会走到数据库,插入慢的时候,老数据可以做封存,也可以建立新表保存新的数据。

如有不合理还请大佬指出
enhancer
2018-05-02 17:29:16 +08:00
不分表的话,不论如何优化都只是暂时的。一个评论表,一般不会在业务上跟其他表有多少 JOIN 关系,上层逻辑按照分表规则 ID 来读取就好,建议分表。
Aluhao
2018-05-02 17:29:58 +08:00
@monsterxx03 因为数量量增加很快,如果走出一个亿查询就会慢了,索引虽然只建了 id 和 aid 二个,但占用空间很大;
cout2013mr
2018-05-02 17:30:29 +08:00
comments 表考虑一下用时间分区?
Aluhao
2018-05-02 17:32:34 +08:00
@enhancer 我们还有一个业务逻辑就是,一个页面要显示一些新闻列表,列表里面又要包含一些新闻的评论,如果分表,这个页面估计就很难实现;

1、新闻 1111
新闻 1 评论 1
新闻 1 评论 2
新闻 1 评论 3
....
2、新闻 2222
新闻 2 评论 1
新闻 2 评论 2
新闻 2 评论 3
....
下面还有
aliipay
2018-05-02 17:35:41 +08:00
@Aluhao 你再仔细看看,分页也容易实现
micean
2018-05-02 17:35:53 +08:00
评论表冗余新闻表的时间用来 partition ?
glacer
2018-05-02 18:08:51 +08:00
优先考虑分区表。分区表在 MySQL 的底层存储同样也是多表,不同分区的数据和索引都是独立的 idb 文件,和分表区别不大,还不需要修改业务代码。
若用评论时间来作为 key 进行分区,楼主的部分业务逻辑虽然不需要改代码,但涉及到跨分区的查询依然无法提高性能,还可能比未分区前性能更低。
我建议对 aid 来进行 hash 分区,即对 aid 的值求 hash 后对分区数 n 取模,这样不会造成明显的数据倾斜现象。MySQL 有现成的 hash 分区。
缺点就是分区数固定,不好扩展,但要是能预估好表的大小,分区数可以设置多一些,问题也不是很大。
monsterxx03
2018-05-02 18:16:55 +08:00
慢的查询 pattern 是什么, 才一个亿, IOPS 没饱和的话,index 设计合理,这个量级不会慢的, 就算你分了表,或者把 content, comment 拆出去, 如果这两个索引是确实需要的话, index size 还是那么大.

建议和楼上一样, 用 MySQL 自己的 partition table, 对 aid 做 hash 分区, 时间分区如果你逻辑总是加在最新的文章的话,会造成热点, 意义不大.
MasterC
2018-05-02 18:37:24 +08:00
@glacer #14 根据新闻 aid 进行 hash 分区取模存储,表面上看是不会造成数据倾斜,但是实际上 每个新闻的评论数都不同,热点新闻和一般新闻的评论数天差地别,所以最终依然会有数据倾斜的问题
Aluhao
2018-05-02 18:38:10 +08:00
@monsterxx03
@glacer
感谢建议!
monsterxx03
2018-05-02 18:52:24 +08:00
还有 db engine 为什么是 MyISAM? 写入会锁表啊
akira
2018-05-02 19:40:46 +08:00
优化都是针对性的,需要有明确的瓶颈点别人才好给优化方案和意见。 不然 只能给出来的就是泛泛而谈了
enenaaa
2018-05-02 19:50:00 +08:00
只是嫌查询慢的话, 何不简单除暴地加缓存, 或者建个小表,存放热门内容。

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

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

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

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

© 2021 V2EX