我正在使用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会为我填充计数字段?
由于
答案 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,您可以查看索引或物化视图等内容。将计数作为表的一部分并尝试维护它几乎肯定是一个错误,特别是对于数据库的小尺寸。