Test data
CREATE TABLE parent AS ( SELECT ROWNUM AS id, 'XXX' AS dummy FROM dual CONNECT BY ROWNUM <= 1000 );
CREATE UNIQUE INDEX idx_parent ON parent(id);
CREATE TABLE child AS ( SELECT CEIL(ROWNUM/5) AS id, 'XXX' AS dummy FROM dual CONNECT BY ROWNUM <= 5000 );
CREATE INDEX idx_child ON child(id);
EXEC dbms_stats.gather_table_stats(USER, 'parent');
EXEC dbms_stats.gather_table_stats(USER, 'child');
Problem
The following query does a full table scan (both with 12.1 and 19.0) on child even though the CARDINALITY hint is considered.
Of course the real query needs some additional data from child.
SELECT child.id
FROM parent
JOIN
(
SELECT child.id
FROM child
GROUP BY child.id
) child ON ( child.id = parent.id )
WHERE parent.id IN ( SELECT /*+ CARDINALITY( tab 1 ) */ COLUMN_VALUE FROM TABLE (sys.odcinumberlist(1) ) tab );
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 19 | 35 (3)| 00:00:01 |
|* 1 | HASH JOIN RIGHT SEMI | | 1 | 19 | 35 (3)| 00:00:01 |
| 2 | COLLECTION ITERATOR CONSTRUCTOR FETCH| | 1 | 2 | 29 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 1000 | 17000 | 6 (17)| 00:00:01 |
| 4 | VIEW | | 1000 | 13000 | 6 (17)| 00:00:01 |
| 5 | HASH GROUP BY | | 1000 | 4000 | 6 (17)| 00:00:01 |
| 6 | TABLE ACCESS FULL | CHILD | 5000 | 20000 | 5 (0)| 00:00:01 |
|* 7 | INDEX UNIQUE SCAN | IDX_PARENT | 1 | 4 | 0 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
Both indexes are used as expected if I replace the WHERE clause by this:
WHERE parent.id IN ( 1 );
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 35 | 2 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 5 | 35 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | IDX_PARENT | 1 | 4 | 1 (0)| 00:00:01 |
| 3 | VIEW | | 5 | 15 | 1 (0)| 00:00:01 |
| 4 | SORT GROUP BY | | 5 | 20 | 1 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN| IDX_CHILD | 5 | 20 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------
It also works when I remove the GROUP BY.
Any idea how to work around that?