SQL会计算多对多的值,还是每次添加新行时都计算它?

时间:2010-01-27 15:16:44

标签: sql mysql count many-to-many

我正在使用MySQL(MyISAM)5.0.41,我有这个查询:

SELECT `x`.`items`.id, `x`.`items`.name, COUNT(*) AS count
    FROM `x`.`items` INNER JOIN `x`.`user_items`
    ON `x`.`items`.id = `x`.`user_items`.item_id
    GROUP BY name HAVING count > 2 ORDER BY count DESC

我有大约36,000个用户,175,000个user_items和60,000个不断添加的项目。所以这个查询有点慢......

是否更好:

  • count中设置items字段并定期更新(例如每次用户添加项目时)
  • 或像这样(慢慢地)运行查询..

或者是否有任何SQL会为我填充计数字段?

由于

5 个答案:

答案 0 :(得分:3)

您可以使用中间解决方案:

  • ts DATETIME表格中添加user_items列,用于说明用户添加项目的时间

  • ts DATETIME表中添加一个users列,用于描述实际情况,只要cnt,缓存的计数列

  • 使用新计数和时间戳定期更新users表:

    INSERT
    INTO    users (id, ts, cnt)
    SELECT  *
    FROM    (
            SELECT  user_id, NOW() AS nts, COUNT(*) AS ncnt
            FROM    user_items ui
            WHERE   ui.timestamp <= NOW()
            )
    ON DUPLICATE KEY
    UPDATE  ts = nnow,
            cnt = ncnt
    
  • 删除user_items条目时,用户的时间戳无效

  • 发出此查询以计算项目:

    SELECT  u.id, u.cnt +
            (
            SELECT  COUNT(*)
            FROM    user_items ui
            WHERE   ui.ts > u.ts
                    AND ui.user_id = u.id
            )
    FROM    users
    

这样,只会在user_items表中计算新添加的项目,这样会快得多,并且您不会经常更新记录时出现并发问题。

答案 1 :(得分:2)

您应该首先索引user_items.item_id并对其进行分组而不是名称。字符串分组要慢得多(自己试试),索引应该加快速度。如果仍然太慢,您可以先运行GROUP BY查询,然后如果您的DBMS执行计划默认情况下没有这样做,则可以加入项目表。

答案 2 :(得分:1)

该查询几乎每次都进行全表扫描。没有办法解决这个问题。索引会加快我的加速速度,但随着数据的增长,查询会变得越来越慢。

存储摘要数据,例如“计数”和“项目”将是可行的方法。您可以使用存储过程或代码执行此操作。作为双重检查,您可以定期(即每天一次)更新所有计数,以便您知道它们是准确的。

答案 3 :(得分:0)

我的冲动是将数据保留为正常形式(换句话说,不要增加“计数”字段),然后缓存应用程序中慢查询的结果水平。

如果缓存无效,因为许多人正在进行查询,而且很少有人这样做两次,那么,是的,您可以设置一个存储过程来自动更新某些表中的某些行。详细信息因数据库供应商而异。这是how to do it in Postgresql。由于竞争条件,这是唯一安全的方法(即在DB内,而不是从应用程序层)。

答案 4 :(得分:0)

每次运行查询时,您是否真正获得了36,000名用户?如果您正在寻找性能问题的根源,那么它就可以就在那里。

根据您的RDBMS,您可以查看索引或物化视图等内容。将计数作为表的一部分并尝试维护它几乎肯定是一个错误,特别是对于数据库的小尺寸。