【问题标题】:How to improve count performance without indexing more fields?如何在不索引更多字段的情况下提高计数性能?
【发布时间】:2012-02-20 19:50:16
【问题描述】:

表中有超过200万条记录。

我想统计表中有多少错误(已检查)以及已检查的错误数。

我做了两个查询:

SELECT count(*) as CountError FROM table WHERE checked = 1 AND error != ''

-

SELECT count(*) as Checked FROM table WHERE checked = 1

性能真的很慢,大约需要5分钟才能得到结果。如何改进?

我已经在status 字段上建立了更新性能的索引。

如果我在 checked 字段上建立索引 - 那么 UPDATE 性能将受到影响,这是我不希望的。

UPDATE 发生的次数比 SELECT 多。

桌子是Innob

【问题讨论】:

  • 购买更多硬件。不,真的 - 你不能一劳永逸,所以如果你不愿意做出权衡,你需要改变问题的约束。使用memcache,或者更快的机器,或者升级数据库软件...
  • 这是一个非常基本的查询。如果不索引 checkederror,您将无能为力。 @Borealid 好的,不过是购买更多硬件......
  • 如果添加索引节省的资源大于添加索引的资源成本,则添加索引。通常,您会发现添加索引的好处多于成本。除非您可以量化没有整体节省,否则我通常会在添加所需内容方面犯错,而不是过度“担心”对更新的影响。

标签: mysql sql database indexing


【解决方案1】:

如果在同一个查询中进行两个计数更快,您可以尝试:

select
  count(*) as CountError,
  sum(case when error != '' then 1 else 0 end) as Checked
from table
where checked = 1

但是,差异可能不会太多。如果你真的想要不同,那么你需要添加一个索引。考虑影响的真正含义,并进行实际测试以了解影响的真正含义。如果更新速度慢 10%,而选择速度快 100000%,那么它可能仍然值得。

【讨论】:

  • 据我所知,第二个聚合在 MySQL 中可能更简单:SUM(error != '') AS Checked(在这种情况下,布尔值隐式转换为整数:false -> 0, true ->1).
【解决方案2】:

您的问题只是您的选中字段是 1 或 0,这意味着即使您有一个键,MySQL 也需要进行表扫描,因为它无法有效地确定 0 和 1 之间的分割位置,尤其是在大量的行。

我要提供的主要建议是您不想要的建议,即检查索引,因为SELECT SUM(checked) AS Checked FROM table WHERE checked=1 将能够使用索引而不会撞到桌子。

最终,这不是一个简单的查询。您可能希望查看一些归档计数的方式。如果您有日期或时间戳,那么您可以每天设置一个任务,该任务可以存储前一天的计数(*)。反过来,这将使您可以在运行时解析更少的行。

如果没有关于此表的确切用途的更多信息,您不允许在该列上建立索引的原因等。很难提出比上述 + 扔硬件更有用的建议。

【讨论】:

  • 没错,如果没有足够的选择性,索引是没有用的。
  • 它们的用途仍然有限,但仅从索引可用于需要有限列的实例的角度来看。不过,对于大多数用途而言,与具有更大范围(即日期范围)的索引相比,它们几乎没有改进
  • true,覆盖索引的索引扫描比表扫描更有效
猜你喜欢
  • 2010-09-19
  • 1970-01-01
  • 1970-01-01
  • 2015-07-01
  • 2017-04-20
  • 2010-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多