I have a simple Oracle query with a plan that doesn't make sense.
SELECT
u.custid AS "custid",
l.listid AS "listid"
FROM
users u
INNER JOIN lists l ON u.custid = l.custid
And here’s what the autotrace explain tells me it has for a plan
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1468K| 29M| | 11548 (1)| 00:00:01 |
|* 1 | HASH JOIN | | 1468K| 29M| 7104K| 11548 (1)| 00:00:01 |
| 2 | INDEX FAST FULL SCAN| USERS_PK | 404K| 2367K| | 266 (2)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | LISTS | 1416K| 20M| | 9110 (1)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("U"."CUSTID"="L"."CUSTID")
3 - filter(TRUNC("SORT_TYPE")>=1 AND TRUNC("SORT_TYPE")<=16)
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- this is an adaptive plan
- 1 Sql Plan Directive used for this statement
What concerns me is predicate 3. sort_type
does not appear in the query, and is not indexed at all. It seems to me that sort_type
should not be involved in this query at all.
There is a constraint on lists.sort_type
: (Yes, I know we could have sort_type
be an INTEGER not a NUMBER)
sort_type NUMBER DEFAULT 2 NOT NULL,
CONSTRAINT lists_sort_type CHECK ( sort_type BETWEEN 1 AND 16 AND TRUNC(sort_type) = sort_type )
It looks to me that that filter is on sort_type
is basically a tautology. Every row in lists
must pass that filter because of that constraint.
If I drop the constraint, the filter no longer shows up in the plan, and the estimated cost goes down a little bit. If I add the constraint back, the plan uses the filter again. There's no significant difference in execution speed one way or the other.
I'm concerned because I discovered this filter in a much larger, more complex query that I was trying to optimize down from a couple of minutes of runtime.
Why is Oracle adding that filter, and is it a problem and/or pointing to another problem?
EDIT: If I change the constraint on sort_type
to not have the TRUNC
part, the filter disappears. If I split the constraint into two different constraints, the filter comes back.