在查询之前预取行计数 - 性能

时间:2012-07-25 16:52:46

标签: sql

我最近根据自己的经验回答了这个问题:

Counting rows before proceeding to actual searching

但我对我给出的答案并不是100%满意。

问题基本上是这样的:在决定运行带回实际行的查询之前,是否可以通过在特定查询上运行COUNT来提高性能?

我的直觉是这样的:你只会保存与检索数据而不是计数相关的I / O和连线时间,因为要计算数据,你需要实际找到行。可能的例外是当查询是索引的简单函数时。

我的问题是:这总是如此吗?还有哪些其他例外情况?从纯粹的性能角度来看,在运行完整查询之前,在什么情况下人们想要COUNT

1 个答案:

答案 0 :(得分:1)

首先,您的问题的答案高度依赖于数据库。

在查询之前执行COUNT()会缩短查询和count()的总时间时,我无法想到这种情况。

通常,执行计数会将表和索引预先加载到页面缓存中。假设数据适合内存,这将使后续查询运行得更快(尽管如果您有快速I / O并且数据库执行预读页面读取速度不是更快)。但是,您刚刚将时间范围转移到COUNT(),而不是缩短总时间。

要缩短总时间(包括COUNT()的运行时间),需要更改执行计划。理论上可以采用以下两种方式:

  1. 数据库可以在读入表时更新统计信息,这些统计信息又会更改主查询的查询计划。
  2. 数据库可以根据表/索引是否已经在页面缓存中来更改执行计划。
  3. 虽然理论上可行,但我不知道有任何数据库可以执行其中任何一项。

    您可以想象可以存储中间结果,但这会违反SQL数据库的动态特性。也就是说,COUNT()和查询之间的表上可能会发生更新/插入。数据库引擎无法保持完整性并保持这样的中间结果。

    相对于加速后续查询,执行COUNT()有一些缺点。 COUNT()的查询计划可能与主查询的查询计划完全不同。您的索引示例是一个案例。另一种情况是在柱状数据库中,不需要读取数据的不同垂直分区。

    另一种情况是查询,例如:

    select t.*, r.val
    from table t left outer join
         ref r
         on t.refID = r.refID
    

    和refID是ref表的唯一索引。对于计数,可以消除此连接,因为没有重复项并且使用t中的所有记录。但是,此查询显然需要连接。再一次,SQL优化器是否识别并对此情况起作用完全取决于数据库的编写者。但是,理论上可以针对COUNT()优化连接。