【发布时间】:2012-10-07 11:03:36
【问题描述】:
我目前经营一个网站,该网站在列表中跟踪最新分数和评级。该列表有数千个经常更新的条目,并且该列表应该可以按这些分数和评级列进行排序。
我获取这些数据的 SQL 目前看起来像(大致):
SELECT e.*, SUM(sa.amount) AS score, AVG(ra.rating) AS rating
FROM entries e
LEFT JOIN score_adjustments sa ON sa.entry_id = e.id
HAVING sa.created BETWEEN ... AND ...
LEFT JOIN rating_adjustments ra ON ra.entry_id = e.id
HAVING ra.rating > 0
ORDER BY score
LIMIT 0, 10
表格在哪里(简化):
entries:
id: INT(11) PRIMARY
...other data...
score_adjustments:
id: INT(11), PRIMARY
entry_id: INT(11), INDEX, FOREIGN KEY (entries.id)
created: DATETIME
amount: INT(4)
rating_adjustments:
id: INT(11), PRIMARY
entry_id: INT(11), INDEX, FOREIGN KEY (entries.id)
rating: DOUBLE
大约有 300,000 个score_adjustments 条目,并且它们以每天大约 5,000 个的速度增长。 rating_adjustments 大约是那个的 1/4。
现在,我不是 DBA 专家,但我猜一直调用 SUM() 和 AVG() 并不是一件好事——尤其是当 sa 和 ra 包含数十万条记录时——对吧?
我已经对查询进行了缓存,但我希望查询本身快速 - 但仍尽可能保持最新。我想知道是否有人可以分享任何解决方案来优化像这样的繁重的连接/聚合查询?如有必要,我愿意进行结构更改。
编辑 1
添加了有关查询的更多信息。
【问题讨论】:
-
实际查询会更好。
-
几个索引通常可以解决问题,但是如果没有表结构、当前索引、实际查询和数据量,那就只能猜测了。在我们得到所有这些之后,这只是猜测。
-
@ypercube 添加了查询的近似表示
-
@GolezTrol 我已经添加了表结构
-
@Ryall 更新了我的答案,包括一个带有示例触发器的 sqlfiddle。
标签: mysql database-design database-optimization