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 表的数据大小,我们必须减小数据大小。为此,我们有多种选择:

mysql 分区:在 user_id 范围内创建分区(每个分区可能有 100K 个用户 创建多个表:类似于分区,但您将拥有不同数据库中的数据(甚至在不同的数据库服务器中)。根据 user_id,您将决定要加入的表/数据库。

此外,您可以考虑定期归档旧数据,并且应用程序应该足够智能以决定是否需要查询归档表或实时表。

【讨论】:

谢谢我在我的问题中更改了查询,但这不是这个问题的主要问题。 分区(或多个表)有什么帮助? 大型 .ibd(data) 文件运行缓慢的原因。通过创建分区或多个表,您正在创建更小的(索引)文件。因此,如果我查询 user_id=1,我不需要在只有 user_ids > 100000 的分区中搜索 如果你有一个以user_id 开头的索引,它同样快。 分区将减少索引长度并创建更小的 ibd 文件。分区可以在内部被视为较小的表。一旦您跨越 1 亿条记录,即使是索引查询,您也会看到一些缓慢。另外我在某处读过,不建议使用 3 亿条记录的表格

以上是关于mysql中获取未读文章的数据库设计(超过100M行表)的主要内容,如果未能解决你的问题,请参考以下文章

如何从mysql获取未读消息

解决用PLSQL Developer查询时数据大小超过100M的提示问题

git 超过100M文件的解决方法

Github如何上传超过100M的大文件

GitHub上传文件不能超过100M的解决办法

请问,如何用bat 删除指定目录下的大小超过100M的文件?比如删除D:\Templates下的超过100M的文件?