【问题标题】:Why does %cpu and cost increase for this execution plan?为什么此执行计划的 %cpu 和成本会增加?
【发布时间】:2020-08-07 22:07:58
【问题描述】:

我有一张表格,里面有很多行记录。我在为查询创建索引之前解释并显示执行计划

explain plan for
SELECT l_partKey, count(*)
FROM LINEITEM
GROUP BY L_PARTKEY
HAVING COUNT(l_tax) > 2;

SELECT * FROM table(dbms_xplan.display);

这是输出

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2487493660

--------------------------------------------------------------------------------
| Id  | Operation           | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |          |  3023 | 15115 |  8821   (1)| 00:00:01 |
|*  1 |  FILTER             |          |       |       |            |          |
|   2 |   HASH GROUP BY     |          |  3023 | 15115 |  8821   (1)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| LINEITEM |  1800K|  8789K|  8775   (1)| 00:00:01 |
--------------------------------------------------------------------------------

然后我创建这个索引:

CREATE INDEX lineItemIdx ON LINEITEM(l_partKey);

再次解释并显示执行计划,这是输出:

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 573468153
--------------------------------------------------------------------------------
------

| Id  | Operation              | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |             |  3023 | 15115 |  1130   (5)| 00:00:01 |
|*  1 |  FILTER                |             |       |       |            |          |
|   2 |   HASH GROUP BY        |             |  3023 | 15115 |  1130   (5)| 00:00:01 |
|   3 |    INDEX FAST FULL SCAN| LINEITEMIDX |  1800K|  8789K|  1084   (1)| 00:00:01 |

有谁知道为什么 %cpu 从 1、1、1 变为 5、5、1?

之后,我删除了我创建的索引,并在 l_partKey、l_tax 上创建了一个新索引,并再次解释和显示执行:

CREATE INDEX lineItemIdx ON LINEITEM(l_partKey, l_tax);


PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
Plan hash value: 573468153

--------------------------------------------------------------------------------
------

| Id  | Operation              | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |             |  3023 | 15115 |  1326   (4)| 00:00:01 |
|*  1 |  FILTER                |             |       |       |            |          |
|   2 |   HASH GROUP BY        |             |  3023 | 15115 |  1326   (4)| 00:00:01 |
|   3 |    INDEX FAST FULL SCAN| LINEITEMIDX |  1800K|  8789K|  1281   (1)| 00:00:01 |

现在,与我之前创建的索引相比,使用新索引 l_partKey, l_tax 时,成本从 1130、1130、1084 到 1326、1326、1281 略有增加。为什么呢?这个索引不应该比之前的索引提高查询处理的速度吗?

【问题讨论】:

    标签: sql oracle indexing


    【解决方案1】:

    您的查询需要计算 1.8 兆行表中的所有行。因此,Oracle 必须进行某种全扫描来满足它。

    没有有用的索引,它需要一个全表扫描:它必须读取整个表。这可能会猛烈抨击服务器的 IO 操作;因此 CPU 在查询经过的时间的一小部分内处于活动状态。 DBMS 有两件事会减慢它们的速度。 IO(从磁盘读取整个表)和 CPU(计算事物)。在没有索引的情况下,CPU 会花费大部分查询的运行时间在磁盘上等待传递整个表的内容。因此 CPU 在经过的时间的一小部分处于活动状态。有了索引,磁盘必须传递更少的数据。因此 CPU 占用了总时间的较大百分比。 CPU% 不能很好地衡量查询的总体成本。

    当您添加第一个索引时,您减少了满足查询所需的 IO 操作,因此 cpu 在更大百分比的已用时间中处于活动状态。

    您的第二个索引导致您的查询花费与您的第一个索引几乎完全相同。索引项有点大,所以 Oracle 需要做更多的工作来处理它们;这可以解释成本的轻微增加。

    不要忘记:Oracle 已经 43 岁了,版本为 19。几代程序员都在努力优化它。试图以很小的成本差异来猜测“为什么”可能不值得您费心。

    最后,您的查询有些奇怪。你先做SELECT ... COUNT(*) 然后HAVING COUNT(column) > 2COUNT(column)COUNT(*) 不同:前者计算 column 中的 non-null 条目,而 COUNT(*) 计算所有条目。这是你的意图吗?

    两个带有索引的查询都使用INDEX FAST FULL SCAN。这是全扫描的圣杯。您的第二个索引包括您的 l_tax 列,因此可以猜测它已声明为 NOT NULL 或者它可能不符合快速扫描的条件。在这种情况下,Oracle 知道 COUNT(*)COUNT(l_tax) 相同。这就是为什么两个索引都提出了相同的计划,即使步骤上的成本略有不同。

    【讨论】:

    • 对不起,我还是不明白,为什么在没有索引需要读取整个表的时候,cpu 的活跃度只有很小的百分比? cpu不应该很大吗?因为它需要大量阅读?
    • DBMS 有两件事会减慢它们的速度。 IO(从磁盘读取整个表)和 CPU(计算事物)。在没有索引的情况下,CPU 会花费大部分查询的运行时间在磁盘上等待传递整个表的内容。因此 CPU 在经过的时间的一小部分处于活动状态。有了索引,磁盘必须传送更少的数据。因此 CPU 占用了总时间的较大百分比。 CPU% 不能很好地衡量查询的总体成本。
    猜你喜欢
    • 1970-01-01
    • 2016-03-05
    • 1970-01-01
    • 2010-12-20
    • 2016-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多