首先,我知道它们是完全不同的东西,不能直接比较,但让我解释一下我的问题。我想存储民意调查以及投票的投票,用户可以从中选择 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操作。
那么,当我们每月讨论数千个操作时,哪个选项更有效,更少服务器负载?
答案 0 :(得分:2)
您的第二种选择(在JSON对象中存储选民的用户ID)比第一种选择远远差。
为什么呢?它不会扩大规模。要记录对项目的第50,000次投票的投射,您必须读取大型JSON对象,修改它,并使用UPDATE操作在数据库中覆盖它。这将需要很长时间。
第八万名选民从高到低改变投票的情况怎么样?这样做会有多复杂。
在您的第一个选择中,每个新投票只需要一个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
此示例为您提供过去一周内投票率最高的用户
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