gpt4 book ai didi

sql - WHERE 与 HAVING 性能与 GROUP BY

转载 作者:行者123 更新时间:2023-12-04 15:17:54 26 4
gpt4 key购买 nike

所以我被分配去估计两个查询的性能并得出了一个令人惊讶的结果。我事先被告知 HAVINGWHERE 慢因为它只在访问行后过滤结果。这似乎很合理,而且this question on SQL clause execution order加强了这一点。
但是,我根据一些假设估计了以下查询的性能,并且似乎使用了 HAVING执行实际上更快!

SELECT status, count(status)
FROM customer
GROUP BY status
HAVING status != 'Active' AND status != 'Dormant'

SELECT status, count(status)
FROM customer
WHERE status != 'Active' AND status != 'Dormant'
GROUP BY status
假设是:
  • CUSTOMER有 100 000 条记录
  • 访问一行的成本是 0.01ms (SELECT + COUNT)
  • 执行一个子句的成本是 0.005ms
  • 客户状态分为三种类型,上述两种和“已故”
  • 有 15 000 个“已故”客户

  • 基于此,我的估计是:
    First query:
    Accessing all rows, FROM: 100 000 * 0.01ms = 1000ms
    GROUP BY: 100 000 * 0.005ms = 500ms
    HAVING (2 conditions, 3 groups): 2 * 3 * 0.005ms = 0.03ms
    SELECT and COUNT results: 15 000 * 0.01ms = 150ms
    Total execution time: 1.65003s

    Second query:
    Accessing all the rows, FROM: 1000ms
    WHERE: 2 * 100 000 * 0.005ms = 1000ms
    GROUP BY: 15 000 * 0.005ms = 75ms
    SELECT and COUNT results: 15 000 * 0.01ms = 150ms
    Total execution time: 2.225s
    结果来自 GROUP BY只产生三组,很容易过滤,而 WHERE必须一一浏览和过滤记录。
    由于我天真地依赖权威,我假设我要么在某处犯了错误,要么提供的假设是错误的。
    GROUP BY也是如此用 HAVING 表现得像这样导致执行时间减少?
    编辑:查询计划
    PLAN_TABLE_OUTPUT /* With HAVING */

    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    ------------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 5 | 35 | 4 (25)| 00:00:01 |
    |* 1 | FILTER | | | | | |
    | 2 | HASH GROUP BY | | 5 | 35 | 4 (25)| 00:00:01 |
    | 3 | TABLE ACCESS STORAGE FULL| CUSM | 5 | 35 | 3 (0)| 00:00:01 |
    ------------------------------------------------------------------------------------

    Predicate Information (identified by operation id):
    ---------------------------------------------------
    1 - filter("STATUS"<>'Active' AND "STATUS"<>'Dormant')


    PLAN_TABLE_OUTPUT /* With WHERE */
    -----------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    -----------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 1 | 7 | 4 (25)| 00:00:01 |
    | 1 | HASH GROUP BY | | 1 | 7 | 4 (25)| 00:00:01 |
    |* 2 | TABLE ACCESS STORAGE FULL| CUSM | 1 | 7 | 3 (0)| 00:00:01 |
    -----------------------------------------------------------------------------------

    Predicate Information (identified by operation id):
    ---------------------------------------------------
    2 - storage("STATUS"<>'Active' AND "STATUS"<>'Dormant')
    filter("STATUS"<>'Active' AND "STATUS"<>'Dormant')

    最佳答案

    事情是这样的:

  • 根据Oracle执行计划,两个查询都在执行全表扫描。也就是说,他们正在阅读 所有行 表的。那里没有区别。
  • HAVING 查询执行 GROUP BY(散列),结果为 3 行。然后,它将过滤器应用于这 3 行,并返回结果。
  • WHERE 查询在读取后将过滤器应用于每一行(规范中的 100,000),将它们减少到 15,000。最后,它将这些(散列)分组为 1 行,并返回一行。

  • 我认为在您所描述的情况下,WHERE 查询将过滤器应用于所有 100,000 行,而 HAVING 查询推迟过滤器并仅将其应用于 3 行。这使得 HAVING 查询更快。

    现在,不要假设此结果将适用于您这样的每个查询。 Oracle 在使用表统计信息方面非常聪明。计划将来会根据您添加到表中的真实数据而改变。 5 行的计划绝不代表 100,000 行的计划。

    对这个结果持保留态度。现实世界的场景要复杂得多。

    关于sql - WHERE 与 HAVING 性能与 GROUP BY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49758446/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com