mysql中获取未读文章的数据库设计(超过100M行表)
Posted
技术标签:
【中文标题】mysql中获取未读文章的数据库设计(超过100M行表)【英文标题】:Database design for getting unread article in mysql (over 100M row table) 【发布时间】:2015-10-11 18:11:04 【问题描述】:这些信息非常简洁。
有 2 张桌子。
文章
-----------------------------------
|id | weight | text |
-----------------------------------
|1 | 10 | blah |
|2 | 100 | blah |
|3 | 50 | blah |
|4 | 1000 | blah |
-----------------------------------
阅读
-----------------------------------
| user_id | article_id |
-----------------------------------
| 1 | 4 |
| 1 | 2 |
| 1 | 3 |
| 2 | 3 |
| 2 | 4 |
-----------------------------------
我想使用以下查询获取未读文章(非常简洁)
SELECT
a.*
FROM
article a LEFT OUTER JOIN read r ON r.article_id = a.id and r.user_id = 1
WHERE
r.id IS NULL
ORDER BY
a.weight DESC
LIMIT 10
重要信息
read table
行数保持在每个用户 1000 以下。 (删除旧数据) 文章表中的重量列经常更改。 (表示顺序不固定)
问题是..(当用户数量:超过 100 万时)
-
使用读表获取未读文章的方法(不在,外连接不重要)
read table
行数将超过 1G
到目前为止它运行良好(当前读取表行数:100M)。但我必须准备下一步,因为用户数量正在迅速增加。
在这种情况下,大型服务的最佳方式是什么?
(分片?分区表?还是重新设计架构?)
提前致谢
【问题讨论】:
使用not exists
或左连接代替not in
。
谢谢,但这不是这个问题的主要问题。我已经尝试过了,发现性能没有太大差异,因为查询计划是由数据库优化的。
我认为这样就好了,假设你有正确的索引和数据类型
那张桌子上有什么索引?
@kimwz.kr 读取表中的 id 列在哪里(r.id 为空)。您在示例查询中引用它?此外,您的查询使用 r.user_id = 1。它总是 1 吗?
【参考方案1】:
向article
添加一列。这将是一个标志,表明文章是否已读/未读。 (不要将其作为用户计数或时间戳;这会减慢后续步骤的速度。)
每当用户阅读文章时,检查标志并根据需要进行更改。
拥有 `INDEX(flag, weight, id) -- 这将使您的查询几乎立即运行。在那张百万行的表上应该没问题。
一个问题:由于您正在清除(1000 之后),一些“已读”文章可能会变成“未读”。为了解决这个问题,请批量清除,并收集被清除的不同文章列表。然后执行重新计算标志的繁琐任务,但仅针对那些文章。 INDEX(article_id)
会有所帮助;使用EXISTS ( SELECT * FROM read WHERE article_id = $aid )
。 (这可能会变成一个批处理操作,而不是一次一个辅助。)
另一个问题:十亿行表上的辅助键成本很高——它们可能会导致大量 I/O。在尝试解决此问题之前,请为这两个表提供SHOW CREATE TABLE
,以及任何其他常见的SELECTs
。选择正确的索引和数据类型对于十亿行表的性能非常很重要。
【讨论】:
【参考方案2】:重点是,尽量使用索引。
SELECT a.*
FROM a
LEFT JOIN read r
ON r.article_id = a.id and r.user_id =1
WHERE r.id IS NULL
ORDER BY a.weight DESC
LIMIT 10
编辑:
您关心的是read
表的数据大小,我们必须减小数据大小。为此,我们有多种选择:
此外,您可以考虑定期归档旧数据,并且应用程序应该足够智能以决定是否需要查询归档表或实时表。
【讨论】:
谢谢我在我的问题中更改了查询,但这不是这个问题的主要问题。 分区(或多个表)有什么帮助? 大型 .ibd(data) 文件运行缓慢的原因。通过创建分区或多个表,您正在创建更小的(索引)文件。因此,如果我查询 user_id=1,我不需要在只有 user_ids > 100000 的分区中搜索 如果你有一个以user_id
开头的索引,它同样快。
分区将减少索引长度并创建更小的 ibd 文件。分区可以在内部被视为较小的表。一旦您跨越 1 亿条记录,即使是索引查询,您也会看到一些缓慢。另外我在某处读过,不建议使用 3 亿条记录的表格以上是关于mysql中获取未读文章的数据库设计(超过100M行表)的主要内容,如果未能解决你的问题,请参考以下文章