【问题标题】:Should I use count(*) on a very common query or store the number我应该在非常常见的查询中使用 count(*) 还是存储数字
【发布时间】:2014-06-13 14:07:08
【问题描述】:

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

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 

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

-- 编辑--

使用当前模型运行解释后,但匿名(选择操作的 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

【问题讨论】:

  • A.ID_ACTIONB.ID的数据类型是什么?
  • 所有ID都是BIGINTB.DATA其实是很多字段
  • 在 mysql 上运行以下命令并分享问题的结果,explain 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 ,硬编码 B.ID 的一些值
  • 查看查询缓存 (dev.mysql.com/doc/refman/5.5/en/query-cache.html)。如果您没有太多不同的 ID_ACTION,那么这可能对您有用,而无需离开严格的数据库模型。
  • @AbhikChakraborty 为查询添加了解释...看起来不错,不是吗?

标签: mysql database-administration


【解决方案1】:

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

您的 where 过滤器和 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 中需要 count(*) 以返回结果的数千行之前,您应该不会注意到速度很慢。坦率地说,我认为你不会遇到这个问题......所以你应该可以使用你描述的连接和我所做的索引。使用 EXPLAIN EXTENDED 来验证这一点。另请注意,如果您使用的是 INNODB(例如http://dev.mysql.com/doc/refman/5.5/en/innodb-buffer-pool.html),LRU 可能会在这里发挥作用。只是需要注意的事情,您想要实现的概念存在。

【讨论】:

  • 谢谢,在生产环境中,最高用户数约为 10k,所以这似乎是可以接受的。关系数据库上的非关系数据让我很困扰,但我不确定这是我的前任的合理优化还是我可以纠正的错误。
  • 我将添加提到的索引并查看带有 EXPLAIN 的查询执行计划。为了安全起见,我还会检查重复的 ID_ACTION 或 ID。如果你在一个非常弱的盒子上,10k 可能是个问题......但在我见过的大多数生产 SQL 盒子中,这应该没问题。我希望这个查询的缓慢部分实际上是 b.DATA 的表读取,无论如何预计算 COUNT(*) 都无济于事。
  • 我在编辑中添加了一个示例行的计划...您的意见好吗先生?用户有时可能会非常频繁地调用此查询。
  • 看起来不错,是的。运行 SELECT id, count() FROM USER_ACTION GROUP BY id ORDER BY COUNT() DESC LIMIT 5;选择这五个 id 并与他们一起运行解释。但基本上这看起来不错。用户可能会经常调用它......很酷。 LRU 会帮您解决这个问题。
猜你喜欢
  • 2015-10-26
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多