更新频繁的计数器列是否应该单独存储在table中?
Should a counter column with frequent update be stored in a separate table?
我有一个 MySQL/MariaDB 数据库,其中存储了 post。每个post都有一些统计指标,比如post当天的浏览次数、总浏览次数、点赞数等。
现在,我计划在每次发生操作时更新 real-time 中的所有计数器列 - post 获得一个视图,喜欢或不喜欢。这意味着 post_stats
table 会一直更新,而 posts
table 很少更新,大部分时间只会被读取。
table架构如下:
posts(post_id, author_id, 标题, slug, 内容, created_at, updated_at)
post_stats(post_id, total_views, total_views_今天, total_likes, total_dislikes)
两个table用一个post_id
外键连接。目前,table 都使用 InnoDB。来自两个 table 的数据将始终一起查询,以便能够显示 post 及其计数器,因此这意味着将一直使用 INNER JOIN
。统计信息在阅读后立即更新(每次页面浏览)。
我的问题是:
- 为了在 table 增长时获得最佳性能,我是否应该将两个 table 合并为一个,因为
post_status
中的列与 post
直接相关条目,或者我应该将 counter/summary table 与主要 posts
table? 分开
- 为了在 table 增长时获得最佳性能,我是否应该将 MyISAM 用于
posts
table 因为我可以想象 MyISAM 在读取时效率更高,而 InnoDB 在插入时效率更高?
这个问题是这个数据库的普遍问题,也适用于同一数据库中的其他 table,例如 users
( 等计数器 他们 posts,他们写的总评论数,他们写的总posts,等等)和 categories
(该类别中 post 的数量 ,等等)。
编辑 1:每天的观看次数计数器在每天午夜通过 cron 作业重置一次。
编辑 2: 将 posts
和 post_stats
作为两个 table 的原因之一是对缓存的担忧。
对于低流量,KISS -- 将计数器保留在主 post
table 中。 (我假设你已经排除了这种可能性。)
对于高流量,将计数器放在单独的 table 中。但是让我们以不同的方式处理“今天的”计数器。 (这就是你要讨论的。)
对于非常高的流量,收集计数以便每个 click/view/like 可以执行少于 1 次更新。 (“汇总表”超出了这个问题的范围。)
学习一下total_views_today
。您是否必须在每个午夜都进行一次大的“重置”?那是(或将变得)成本太高,所以让我们尽量避免它。
- 在table中只有
total_views
。
- 在午夜将 table 复制到另一个 table。 (
SELECT
比重置值所需的 UPDATE
更快,less-invasive。)通过构建新的 table 来完成此复制,然后 RENAME TABLE
移动它到位。
- 通过减去两个table中的相应值来计算
total_views_today
。
那给你留下了
post_stats(post_id, total_views, total_likes, total_dislikes)
对于“高流量,做就好了
UPDATE post_stats SET ... = ... + 1 WHERE post_id = ...;
在需要的时候(每个计数器)。
但是有一个潜在的问题。如果该行不存在,则不能增加计数器。最好通过在创建 post
的同时创建一个包含零的行来解决这个问题。 (否则,请参阅 IODKU。)
(想多了可能还会回来)
我有一个 MySQL/MariaDB 数据库,其中存储了 post。每个post都有一些统计指标,比如post当天的浏览次数、总浏览次数、点赞数等。
现在,我计划在每次发生操作时更新 real-time 中的所有计数器列 - post 获得一个视图,喜欢或不喜欢。这意味着 post_stats
table 会一直更新,而 posts
table 很少更新,大部分时间只会被读取。
table架构如下:
posts(post_id, author_id, 标题, slug, 内容, created_at, updated_at)
post_stats(post_id, total_views, total_views_今天, total_likes, total_dislikes)
两个table用一个post_id
外键连接。目前,table 都使用 InnoDB。来自两个 table 的数据将始终一起查询,以便能够显示 post 及其计数器,因此这意味着将一直使用 INNER JOIN
。统计信息在阅读后立即更新(每次页面浏览)。
我的问题是:
- 为了在 table 增长时获得最佳性能,我是否应该将两个 table 合并为一个,因为
post_status
中的列与post
直接相关条目,或者我应该将 counter/summary table 与主要posts
table? 分开
- 为了在 table 增长时获得最佳性能,我是否应该将 MyISAM 用于
posts
table 因为我可以想象 MyISAM 在读取时效率更高,而 InnoDB 在插入时效率更高?
这个问题是这个数据库的普遍问题,也适用于同一数据库中的其他 table,例如 users
( 等计数器 他们 posts,他们写的总评论数,他们写的总posts,等等)和 categories
(该类别中 post 的数量 ,等等)。
编辑 1:每天的观看次数计数器在每天午夜通过 cron 作业重置一次。
编辑 2: 将 posts
和 post_stats
作为两个 table 的原因之一是对缓存的担忧。
对于低流量,KISS -- 将计数器保留在主
post
table 中。 (我假设你已经排除了这种可能性。)对于高流量,将计数器放在单独的 table 中。但是让我们以不同的方式处理“今天的”计数器。 (这就是你要讨论的。)
对于非常高的流量,收集计数以便每个 click/view/like 可以执行少于 1 次更新。 (“汇总表”超出了这个问题的范围。)
学习一下total_views_today
。您是否必须在每个午夜都进行一次大的“重置”?那是(或将变得)成本太高,所以让我们尽量避免它。
- 在table中只有
total_views
。 - 在午夜将 table 复制到另一个 table。 (
SELECT
比重置值所需的UPDATE
更快,less-invasive。)通过构建新的 table 来完成此复制,然后RENAME TABLE
移动它到位。 - 通过减去两个table中的相应值来计算
total_views_today
。
那给你留下了
post_stats(post_id, total_views, total_likes, total_dislikes)
对于“高流量,做就好了
UPDATE post_stats SET ... = ... + 1 WHERE post_id = ...;
在需要的时候(每个计数器)。
但是有一个潜在的问题。如果该行不存在,则不能增加计数器。最好通过在创建 post
的同时创建一个包含零的行来解决这个问题。 (否则,请参阅 IODKU。)
(想多了可能还会回来)