我应该在非常常见的查询中使用count(*)还是存储该数字

时间:2014-06-13 14:07:09

标签: mysql database-administration

我有两张桌子(实际上更多,但只对这两张桌子感兴趣)。

USER_ACTION (ID, ID_USER, ID_ACTION, TMST) AS A
ACTION (ID, DATA, NUM_USERS) AS B

但是,B.NUM_USERS实际上是USER_ACTION中具有A.ID_ACTION = B.ID

的记录数的表示。

这是否可以接受为性能优化(一个非常常见的查询经常恢复ACTION数据),或者因为这打破了关系模型,这是一个坏主意,查询应该是:

SELECT B.ID, B.DATA, count(*) AS NUM_USERS 
FROM ACTION B JOIN USER_ACTION A ON A.ID_ACTION = B.ID
WHERE B.ID = ?
GROUP BY B.ID 

如果第二个选项是正确的答案,我是否应该设置任何索引来优化此查询?

- 编辑 -

使用当前模型运行Explain,但是anonimyzed(所选操作的8个用户):

id  select_type table   type    possible_keys       key         key_len     ref     rows    Extra
1   SIMPLE      B       const   PRIMARY             PRIMARY         8       const   1   
1   SIMPLE      A       ref     FK_USER_ACTION  FK_USER_ACTION      8       const   8   Using index

1 个答案:

答案 0 :(得分:0)

我建议按照您的描述保留查询,并在ACTION中的USER_ACTION和ID中的ID_ACTION上添加索引。

您的where filter和group by都将受益于ACTION上的索引,而对USER_ACTION的连接应该是eq_ref连接(更多信息http://www.sitepoint.com/using-explain-to-write-better-mysql-queries/),这在大多数情况下会很快。在查询前使用EXPLAIN EXTENDED来验证操作计划。如果您开始注意到任何缓慢,您还可以使用复合索引(ID,DATA)在ACTION中索引DATA。这会给你一个覆盖索引,但我怀疑使用ID索引DATA的成本是否真的值得(更多信息:http://www.mysqlperformanceblog.com/2006/11/23/covering-index-and-prefix-indexes/ ...旧的,但仍适用)

通常,如果有许多count()是几千行,您可能需要通过物化视图或cron作业或其他来考虑汇总表。计算()超过(例如)100k行的速度仍然比预先计算的要慢。但基本上你不应该注意到很慢,直到你在USER_ACTION中处理数千行需要计数(*)'d才能返回结果。坦率地说,我不认为你会遇到那个问题...所以你应该没问题,你用我所做的指数描述的联接。使用EXPLAIN EXTENDED验证。另请注意,如果您使用INNODB(例如http://dev.mysql.com/doc/refman/5.5/en/innodb-buffer-pool.html),LRU可能会在这里发挥作用。需要注意的是,你想要实现的概念存在。