希望你一切都好。
我需要这个数据库的帮助:
这是一个存储选票的数据库。用户选择他们喜欢的音轨,然后投票给他们。他们可以投票“赞成”或“反对”。非常简单。但是,当涉及到计算数据时,它会变得毛茸茸的。
元
这是一个键值样式表,存储最常用的统计信息(只是某种缓存):
mysql> SELECT * FROM Meta;
+-------------+-------+
| Key | Value |
+-------------+-------+
| TRACK_COUNT | 2620 |
| VOTE_COUNT | 3821 |
| USER_COUNT | 371 |
+-------------+-------+
投票
投票表持有投票本身。这里唯一有趣的字段是Type
, 的值意味着:
0
- 应用程序投票,用户使用 UI 为曲目投票1
- 导入投票(来自外部服务)2
- 合并投票。实际上与 Imported Vote 相同,但它实际上做了一个注释,该用户已经使用外部服务为该曲目投票,现在他正在使用应用程序重复自己。
追踪
轨道是为自己保存总统计数据。喜欢、不喜欢、来自外部服务的喜欢 ( LikesRP
)、来自外部服务的不喜欢 ( DislikesRP
)、喜欢/不喜欢调整的数量。
应用程序
该应用程序需要获得以下投票:
- 过去 7 天内投票最多的 5 首曲目
- 过去 7 天内投票最多的 5 首曲目
- 过去 7 天内投票最多的 5 首曲目,其中的投票来自外部服务 (
Vote.Type = 1
) - 上个月投票最多的 100 首曲目
为了获得 100 个投票最多的曲目,我使用以下查询:
SELECT
T.Hash,
T.Title,
T.Artist,
COALESCE(X.VotesTotal, 0) + T.LikesAdjust as VotesAdjusted
FROM (
SELECT
V.TrackHash,
SUM(V.Vote) AS VotesTotal
FROM
Vote V
WHERE
V.CreatedAt > NOW() - INTERVAL 1 MONTH AND V.Vote = 'up'
GROUP BY
V.TrackHash
ORDER BY
VotesTotal DESC
) X
RIGHT JOIN Track T
ON T.Hash = X.TrackHash
ORDER BY
VotesAdjusted DESC
LIMIT 0, 100;
此查询工作正常,它支持调整(客户想要调整列表中的轨道位置)。几乎相同的查询用于获得 5 个最上/下投票的曲目。任务 #3 的查询是这样的:
SELECT
T.Hash,
T.Title,
T.Artist,
COALESCE(X.VotesTotal, 1) as VotesTotal
FROM (
SELECT
V.TrackHash,
SUM(V.Vote) AS VotesTotal
FROM
Vote V
WHERE
V.Type = '1' AND
V.CreatedAt > NOW() - INTERVAL 1 WEEK AND
V.Vote = 'up'
GROUP BY
V.TrackHash
ORDER BY
VotesTotal DESC
) X
RIGHT JOIN Track T
ON T.Hash = X.TrackHash
ORDER BY
VotesTotal DESC
LIMIT 0, 5;
问题是第一个查询需要大约 2 秒的时间来执行,而我们的票数少于 4k。到年底,这个数字将是大约 20 万张选票,这很可能会扼杀这个数据库。所以我正在想办法解决这个难题。
现在我归结为这些问题:
- 我是否使数据库设计错误?我的意思是,它会更好吗?
- 我是不是查询错了?
- 还有什么我可以改进的吗?
我做的第一件事是缓存。但是,好的,这彻底解决了问题。但我对 SQL 相关的解决方案很好奇(总是倾向于完美)。
我有一个想法的第二件事是将这些计算值放到Meta
表中并在投票过程中更改它们。但是我的时间很短,只是尝试一下。顺便说一句,这值得吗?或者,企业级应用如何解决这些问题?
谢谢。
编辑
我不敢相信我忘了包括索引。他们来了:
mysql> SHOW INDEXES IN Vote;
+-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Vote | 0 | UNIQUE_UserId_TrackHash | 1 | UserId | A | 890 | NULL | NULL | | BTREE | |
| Vote | 0 | UNIQUE_UserId_TrackHash | 2 | TrackHash | A | 4450 | NULL | NULL | | BTREE | |
| Vote | 1 | INDEX_TrackHash | 1 | TrackHash | A | 4450 | NULL | NULL | | BTREE | |
| Vote | 1 | INDEX_CreatedAt | 1 | CreatedAt | A | 1483 | NULL | NULL | | BTREE | |
| Vote | 1 | UserId | 1 | UserId | A | 1483 | NULL | NULL | | BTREE | |
+-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
mysql> SHOW INDEXES IN Track;
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Track | 0 | PRIMARY | 1 | Hash | A | 2678 | NULL | NULL | | BTREE | |
| Track | 1 | INDEX_Likes | 1 | Likes | A | 66 | NULL | NULL | | BTREE | |
| Track | 1 | INDEX_Dislikes | 1 | Dislikes | A | 27 | NULL | NULL | | BTREE | |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+