Astoach167
Astoach167

Reputation: 91

Why does %cpu and cost increase for this execution plan?

I have a table that is populated with many rows of records. I explain and display the execution plan before the creation of the index for a query

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

SELECT * FROM table(dbms_xplan.display);

And this is the output

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 |
--------------------------------------------------------------------------------

Then I create this index:

CREATE INDEX lineItemIdx ON LINEITEM(l_partKey);

Explain and display the execution plan again and this is the output:

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 |

Does anyone know why the %cpu goes from 1, 1, 1 to 5, 5, 1?

Afterwards, I removed the index I created and create a new index on l_partKey, l_tax and explain and display the execution again:

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 |

Now there is a slight increase in cost from 1130, 1130, 1084 to 1326, 1326, 1281, when using the new index l_partKey, l_tax as compared to the previous index i created. Why is that so? Shouldn't this index be increasing the speed of the query processing more than the previous index?

Upvotes: 1

Views: 1154

Answers (1)

O. Jones
O. Jones

Reputation: 108839

Your query requires counting all the rows in a 1.8 megarow table. Therefore, Oracle has to do some kind of full scan to satisfy it.

Without a useful index, it needed a full table scan: it has to read the entire table. That probably slams the server's IO operations; so the cpu is active for a small percent of the elapsed time of the query. DBMSs have two things that slow them down. IO (reading an entire table from disk) and CPU (computing things). Without an index, the CPU spends most of the elapsed time of the query waiting on the disk to deliver the contents of the whole table. So the CPU is active for a smaller percentage of the elapsed time. With the index, the disk must deliver less data. So the CPU takes a larger percentage of the total time. CPU% is not a good measure of the overall cost of queries.

When you added your first index, you reduced the IO operations needed to satisfy the query, so the cpu became active for a larger percent of the elapsed time.

Your second index caused your query to cost almost exactly the same as your first. The index items are a little bit larger so Oracle has to do slightly more work to handle them; that may explain the slight cost increase.

Don't forget: Oracle is 43 years old and on version 19. Generations of programmers have worked to optimize it. Trying to guess "why" for a small cost difference is probably not worth your trouble.

Finally, there's something strange in your query. You do SELECT ... COUNT(*) and then HAVING COUNT(column) > 2. COUNT(column) is different from COUNT(*): the former counts the non-null entries in column, where COUNT(*) counts them all. Is that your intention?

Both queries with indexes use INDEX FAST FULL SCAN. That's the holy grail of full scans. Your second index includes your l_tax column, so it's possible to guess it's declared NOT NULL or it might not have been eligible for fast scanning. In that case Oracle knows COUNT(*) is the same as COUNT(l_tax). That's why both indexes come up with the same plan, even with slightly different costs on the steps.

Upvotes: 2

Related Questions