【问题标题】:Database Design/SQL Optimisation: WHERE <id> NOT IN (thousands of IDs)数据库设计/SQL 优化:WHERE <id> NOT IN(数千个 ID)
【发布时间】:2012-04-30 23:38:25
【问题描述】:

有人要求我向应用程序添加功能,让用户在 A 和 B 两个选项之间进行投票。这些问题的表格非常基本:

QUESTIONS
question_id (PK)
option_id_1(FK)
option_id_2(FK)
urgent (boolean)

每次用户投票时,该用户已投票的信息都会存储在一个同样简单的表中:

USER VOTES
vote_id (PK)
user_id (FK)
question_id (FK)

当用户请求新问题时选择出现哪个问题的算法很复杂,但出于我们的目的,我们可以假设它是随机的。那么,有什么问题吗?

每个用户都会对许多问题进行投票。可能数百,甚至数千。我需要确保没有用户收到他们已经投票过的问题,而我想这样做的唯一方法是,我猜,将服务器打到遗忘状态。具体来说,类似:

SELECT * from questions WHERE question_id NOT in (SELECT question_id from user_votes WHERE user_id = <user_id>) ORDER BY RAND() LIMIT 1. 

[注意:RAND() 实际上不在查询中 - 它只是作为稍微复杂的 (order_by) 的替代品。]

因此,请记住,许多用户很可能已经对数百个甚至数千个问题进行了投票,并且不可能按固定顺序呈现问题...关于如何排除已投票问题的任何想法把我的服务器打到地上?

感谢所有建议 - 非常感谢。

【问题讨论】:

  • RAND() 可能是一个很大的性能缺陷,仅供参考
  • 干杯西蒙。 rand() 只是为了演示目的,它是一个 order_by [bunch of fields]。以上编辑。
  • 可能有助于查看实际订单,只是为了将来参考 :) 看到 RAND() 不同于查看特定标准 :)

标签: mysql performance database-design optimization


【解决方案1】:

JOIN 运算符的性能比 MySQL 中的嵌套查询好得多(这可能会随着最新的 MySQL 版本而改变,但如果你遇到性能问题,我猜我的说法仍然成立)

您可以做的只是将投票留在问题上,然后只选择那些没有投票的记录(没有人投票):

SELECT * 
FROM questions q 
LEFT JOIN user_votes uv ON 
  uv.question_id = q.question_id AND
  uv.user_id = '<user_id>'
WHERE vote_id IS NULL

【讨论】:

  • 很好 - 没想到。谢谢keymone
【解决方案2】:

RAND() 很讨厌,但是这可以缓解问题,同时为您提供所需的结果。看到您提到 RAND() 是一个示例,我真的无法提供比以下更具体的建议,但是替换 ORDER BY 应该可以正常工作。

您能够限制内部查询中的行数越多,整个查询的执行速度就越快。

SELECT
    q.*
FROM (
    -- First get the questions which have not been answered
    SELECT 
        questions.*
    FROM questions 
    LEFT JOIN user_votes 
        ON user_votes.question_id = questions.question_id
        AND user_votes.user_id = <user_id>
    WHERE user_votes.user_id IS NULL
) q
-- Now get a random 1.  I hate RAND().
ORDER BY RAND()
LIMIT 1

【讨论】:

    猜你喜欢
    • 2018-11-14
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    • 2011-08-13
    相关资源
    最近更新 更多