There is a temporary table
CREATE GLOBAL TEMPORARY TABLE "TMP_CONTROL_POINT_DETECT" ( "POINT_ID" NUMBER NOT NULL ENABLE, CONSTRAINT "TMP_CONTROL_POINT_DETECT_PK" PRIMARY KEY ("POINT_ID") ENABLE ) ON COMMIT PRESERVE ROWS ;
And there is a persistent table
CREATE TABLE "CONTROL_POINTS_" ( "ID" NUMBER, "STATUS" NUMBER(1,0), CONSTRAINT "PK_CONTROL_POINTS_" PRIMARY KEY ("ID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS TABLESPACE "USERS" ENABLE );
There are 200 entries in the temporary table, 29,000 in persistent
I make a request
SELECT cp.status FROM TMP_CONTROL_POINT_DETECT det JOIN CONTROL_POINTS_ cp ON ( det.POINT_ID = cp.ID )
and terrified of the plan
----------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 200 | 3800 | 18 (6)| 00:00:01 | |* 1 | HASH JOIN | | 200 | 3800 | 18 (6)| 00:00:01 | | 2 | TABLE ACCESS FULL| TMP_CONTROL_POINT_DETECT | 200 | 2600 | 2 (0)| 00:00:01 | | 3 | TABLE ACCESS FULL| CONTROL_POINTS_ | 29303 | 171K| 16 (7)| 00:00:01 | ----------------------------------------------------------------------------------------------- PLAN_TABLE_OUTPUT --------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("DET"."POINT_ID"="CP"."ID") Note ----- - dynamic statistics used: dynamic sampling (level=2) - this is an adaptive plan
Then I change the selectable field in the request.
SELECT cp.id FROM TMP_CONTROL_POINT_DETECT det JOIN CONTROL_POINTS_ cp ON ( det.POINT_ID = cp.ID )
And get the expected plan
----------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 200 | 3600 | 2 (0)| 00:00:01 | | 1 | NESTED LOOPS | | 200 | 3600 | 2 (0)| 00:00:01 | | 2 | TABLE ACCESS FULL| TMP_CONTROL_POINT_DETECT | 200 | 2600 | 2 (0)| 00:00:01 | |* 3 | INDEX UNIQUE SCAN| PK_CONTROL_POINTS_ | 1 | 5 | 0 (0)| 00:00:01 | ----------------------------------------------------------------------------------------------- PLAN_TABLE_OUTPUT --------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("DET"."POINT_ID"="CP"."ID") Note ----- - dynamic statistics used: dynamic sampling (level=2)
Can anyone explain what is happening? Where does FULL SCAN come from? The query itself selects honest 200 entries.
Type manipulation
SELECT cp.STATUS FROM CONTROL_POINTS_ cp WHERE cp.ID IN (SELECT ID FROM TMP_CONTROL_POINT_DETECT det)
lead to even more depressing consequences
------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5860K| 33M| 2820 (4)| 00:00:01 | | 1 | MERGE JOIN CARTESIAN| | 5860K| 33M| 2820 (4)| 00:00:01 | | 2 | TABLE ACCESS FULL | TMP_CONTROL_POINT_DETECT | 200 | | 2 (0)| 00:00:01 | | 3 | BUFFER SORT | | 29303 | 171K| 2818 (4)| 00:00:01 | | 4 | TABLE ACCESS FULL | CONTROL_POINTS_ | 29303 | 171K| 14 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------
Update
The temporary table has nothing to do with it. With the same persistent structure and the same data the same picture