首先,我知道它们是完全不同的东西,不能直接比较,但让我解释一下我的问题。我想存储民意调查以及民意调查投票,用户只能从Upvote或Downvote中进行选择。我想记录每一个动作,这意味着我必须在数据库中存储更多数据。
在这种情况下,我有两个选择。要么我可以制作两个名为faq
和faq_votes
的表,结构如下:
方法1:
常见问题表列:
id
,question(string)
,answer(text)
,created_at(timestamp)
和updated_at(timestamp)
faq_votes表列:
id
,faq_id(foreign)
,user_id(foreign)
和vote(boolean)
或者我可以将所有内容存储在一个表中,我只需要在faq
表中添加两列。但在这种情况下,我必须以JSON
格式存储投票。
方法2:
常见问题表列:
id
,question(string)
,answer(text)
,upvotes(JSON)
,downvotes(JSON)
,created_at
和updated_at
示例JSON:
{ "total": 5, "users":[ 3,6,10,12,2 ] }
在第一种情况下,我会发出大量的MySQL查询来完成我的工作。在第二种情况下,我会发出更少量的查询,但我必须解决大量的JSON操作。
那么,当我们每月谈论数千个更多的操作时,哪个选项对于提高效率和减少服务器负载更好?
你的第二个替代方案(在jSON对象中存储选民的用户ID)远比你的第一个替代方案差。
为什么?它不会扩大规模。要记录对项目的第50,000次投票的投射,您必须读取大型JSON对象,修改它,并使用UPDATE操作在数据库中覆盖它。这将需要很长时间。
第8万名选民从高到低改变投票的情况怎么样?这样做的操作有多复杂。
在您的第一个选择中,每个新的投票只需要一个INSERT ... ON DUPLICATE KEY UPDATE ...
操作,并简单地在投票表中添加一个新行。 SQL是以这种方式做事的。
编辑以这种方式思考这个问题:
您的实体表将具有user_id
和faq_id
唯一标识符,以及您的应用程序所需的任何其他列。
你的关系表,称之为vote
,每次投票都会有一行。它将user_id
与faq_id
联系起来。此关系表需要三列。
user_id PK FK to user.user_id
faq_id PK FK to faq.faq_id
vote TINYINT 1 or -1
datestamp TIMESTAMP the time of casting the vote.
请注意,vote
表具有复合主键。这用于防止用户针对常见问题进行多次投票。
这样的结构为您提供了非常灵活的报告。例如,此查询将在过去两天内找到最受欢迎的常见问题解答。
SELECT v.faq_id, SUM(v.vote) votes
FROM vote v
WHERE v.datestamp >= CURDATE() - INTERVAL 2 DAY
GROUP BY v.faq_id
ORDER BY SUM(v.vote) DESC
LIMIT 1
此示例为您提供过去一周投下最多downvotes的用户
SELECT v.user_id, u.user_name, COUNT(*) downvotes
FROM vote v
JOIN user u ON v.user_id = u.user_id
WHERE v.vote < 0
AND v.datestamp >= CURDATE() - INTERVAL 1 WEEK
GROUP BY v.user_id, u.user_name
ORDER BY COUNT(*) DESC
LIMIT 1