每日SQL技巧:警惕SELECT COUNT(*)

最近,我在客户站点的各处遇到了这种查询:

DECLARE
  v_var NUMBER(10);
BEGIN
  SELECT COUNT(*)
  INTO   v_var
  FROM   table1
  JOIN   table2 ON table1.t1_id = table2.t1_id
  JOIN   table3 ON table2.t2_id = table3.t2_id
  ...
  WHERE  some_predicate;

  IF (v_var = 1) THEN
    do_something
  ELSE
    do_something_else
  END IF;
END;

不幸的是,当我们要检查某些谓词的关系时, COUNT(*)通常是想到的第一个解决方案。 但是COUNT()非常昂贵,特别是如果我们要做的只是检查我们的关系是否存在 。 这个词会响吗? 是的,我们应该使用EXISTS谓词,因为如果我们不关心为给定谓词返回true的确切记录数,则我们不应该遍历完整的数据集来实际计算确切数 。 上面的PL / SQL块可以简单地重写为这一块:

DECLARE
  v_var NUMBER(10);
BEGIN
  SELECT CASE WHEN EXISTS (
    SELECT 1
    FROM   table1
    JOIN   table2 ON table1.t1_id = table2.t1_id
    JOIN   table3 ON table2.t2_id = table3.t2_id
    ...
    WHERE  some_predicate
  ) THEN 1 ELSE 0 END
  INTO   v_var
  FROM   dual;

  IF (v_var = 1) THEN
    do_something
  ELSE
    do_something_else
  END IF;
END;

让我们测量一下!

查询1产生以下执行计划:
-----------------------------------------------
| Id  | Operation           | E-Rows | A-Rows |
-----------------------------------------------
|   0 | SELECT STATEMENT    |        |      1 |
|   1 |  SORT AGGREGATE     |      1 |      1 |
|*  2 |   HASH JOIN         |      4 |      4 |
|*  3 |    TABLE ACCESS FULL|      2 |      2 |
|*  4 |    TABLE ACCESS FULL|      6 |      6 |
-----------------------------------------------
查询2产生以下执行计划:
----------------------------------------------
| Id  | Operation          | E-Rows | A-Rows |
----------------------------------------------
|   0 | SELECT STATEMENT   |        |      1 |
|   1 |  NESTED LOOPS      |      4 |      1 |
|*  2 |   TABLE ACCESS FULL|      2 |      1 |
|*  3 |   TABLE ACCESS FULL|      2 |      1 |
|   4 |  FAST DUAL         |      1 |      1 |
----------------------------------------------

您可以忽略TABLE ACCESS FULL操作,实际查询是在没有索引的普通数据库上执行的。

但是,最重要的是大大提高了E-Rows值(E =估计值),更重要的是最优A-Rows值(A =实际值)。 如您所见,一旦遇到与谓词匹配的第一个记录,则EXISTS谓词可能会提前中止–在这种情况下,立即终止。

有关如何收集Oracle执行计划的更多详细信息,请参见这篇文章。

结论

每当遇到COUNT(*)操作时,都应该问自己是否真的需要它。 您是否真的需要知道与谓词匹配的记录的确切数量? 还是您已经很高兴知道任何记录与谓词匹配?

答:可能是后者。

翻译自: https://www.javacodegeeks.com/2014/08/sql-tip-of-the-day-be-wary-of-select-count.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值