There’s a thread on the Oracle Database Forum at present where someone has supplied a script to create some data that’s guaranteed to reproduce wrong results (provided your system stats and optimizer parameters are at their default values). They’ve even supplied a link to the script on LiveSQL (opens in new window) – which is running 19.8 – to demonstrate the problem.
I’ve tested on 12.2.0.1 and 19.3.0.0 and the problem occurs in both versions – though with my setup the initial plan that returned the wrong results didn’t re-optimize to a plan with the correct results in 12.2.0.1.
I’ve included a script at the end of the note to create the data set but I’ll describe some of the objects as we go along – starting with a query that gives the correct result, apparently because it’s been hinted to do so:
execute dbms_stats.delete_system_stats set linesize 255 set pagesize 60 set trimspool on alter session set statistics_level='all'; set serveroutput off select /*+ use_hash(dwf) */ count(*) count_hash from test_dwf_sapfi dwf where exists ( select 1 from test_sapfi_coicar_at5dat11 coi where coi.datumzprac = 20200414 and to_char(coi.datuct,'yyyymmdd') = dwf.datumucetnipom_code ); select * from table(dbms_xplan.display_cursor(format=>'cost outline allstats last partition hint_report adaptive'));
test_dwf_sapfi is a table with a single numeric column datumucetnipom_code, the table is list partitioned by that column with 61 partitions. Each partition is defined to hold a single value. The number is designed to look like a date in the format YYYYMMDD.
test_sapfi_coicar_at5dat11 is a table with two columns (datuct, datumzprac). The first column is a date column with data covering a range of 60 dates, the second column is a numeric column and the table is list partioned on that column. All the data in the table is in one partition of that table and the column holds the same value for every row (again it’s a number that looks like a date).
There are 15,197 rows in each table, and the test_dwf_sapfi data has been created as a copy (with a suitable to_number(to_char()) formatting change from the test_sapfi_coicar_at5dat11 table.
Here’s the execution plan from 19c:
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| Pstart| Pstop | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 328 (100)| | | 1 |00:00:00.02 | 155 | 69 | | | | | 1 | SORT AGGREGATE | | 1 | 1 | | | | 1 |00:00:00.02 | 155 | 69 | | | | |* 2 | HASH JOIN RIGHT SEMI | | 1 | 253 | 328 (1)| | | 15197 |00:00:00.02 | 155 | 69 | 2352K| 2352K| 2110K (0)| | 3 | PART JOIN FILTER CREATE | :BF0000 | 1 | 152 | 13 (0)| | | 15197 |00:00:00.01 | 25 | 0 | | | | | 4 | PARTITION LIST SINGLE | | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | 0 | | | | | 5 | TABLE ACCESS FULL | TEST_SAPFI_COICAR_AT5DAT11 | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | 0 | | | | | 6 | PARTITION LIST JOIN-FILTER| | 1 | 15197 | 314 (1)|:BF0000|:BF0000| 15197 |00:00:00.01 | 130 | 69 | | | | | 7 | TABLE ACCESS FULL | TEST_DWF_SAPFI | 60 | 15197 | 314 (1)|:BF0000|:BF0000| 15197 |00:00:00.01 | 130 | 69 | | | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('19.1.0') DB_VERSION('19.1.0') ALL_ROWS OUTLINE_LEAF(@"SEL$5DA710D3") UNNEST(@"SEL$2") OUTLINE(@"SEL$1") OUTLINE(@"SEL$2") FULL(@"SEL$5DA710D3" "DWF"@"SEL$1") FULL(@"SEL$5DA710D3" "COI"@"SEL$2") LEADING(@"SEL$5DA710D3" "DWF"@"SEL$1" "COI"@"SEL$2") USE_HASH(@"SEL$5DA710D3" "COI"@"SEL$2") SWAP_JOIN_INPUTS(@"SEL$5DA710D3" "COI"@"SEL$2") END_OUTLINE_DATA */ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("DWF"."DATUMUCETNIPOM_CODE"=TO_NUMBER(TO_CHAR(INTERNAL_FUNCTION("COI"."DATUCT"),'yyyymmdd'))) Hint Report (identified by operation id / Query Block Name / Object Alias): Total hints for statement: 1 (N - Unresolved (1)) --------------------------------------------------------------------------- 7 - SEL$5DA710D3 / DWF@SEL$1 U - use_hash(dwf)
You’ll notice there’s no “adaptive” information in the report, and there’s no “Note” section saying it’s an adaptive plan. You might also note that the plan looks as if it’s doing a hash join into “dwf” but the “Hint Report” tells us that the hint has not been used and the “Outline Information” tells us that the plan has actually arrived as the result of the combination /*+ use_hash(coi) swap_join_inputs(coi)” */. In fact this is the default plan (on my system) that would have appeared in the complete absence of hints.
The result of the count(*) should be 15,197 – and you can see that this plan has produced the right answer when you check the A-Rows value for operation 2 (the hash join right semi that generates the rowsource for the sort aggregate).
So now we try again but with a hint to generate a nested loop join and it gives us the wrong result (8) and an oddity in the plan. I’ve reported the body of the plan twice, the first version includes the adaptive information the second is the tidier plan we get by omitting the ‘adaptive’ format option:
select count(*) count_nl from test_dwf_sapfi dwf where exists ( select /*+ use_nl (coi) */ 1 from test_sapfi_coicar_at5dat11 coi where coi.datumzprac = 20200414 and to_char(coi.datuct,'yyyymmdd') = dwf.datumucetnipom_code ) ; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| Pstart| Pstop | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 329 (100)| | | 1 |00:00:00.01 | 154 | | | | | 1 | SORT AGGREGATE | | 1 | 1 | | | | 1 |00:00:00.01 | 154 | | | | |- * 2 | HASH JOIN | | 1 | 38491 | 329 (1)| | | 8 |00:00:00.01 | 154 | 3667K| 1779K| | | 3 | PART JOIN FILTER CREATE | :BF0000 | 1 | 38491 | 329 (1)| | | 8 |00:00:00.01 | 154 | | | | | 4 | NESTED LOOPS | | 1 | 38491 | 329 (1)| | | 8 |00:00:00.01 | 154 | | | | |- 5 | STATISTICS COLLECTOR | | 1 | | | | | 60 |00:00:00.01 | 25 | | | | | 6 | SORT UNIQUE | | 1 | 152 | 13 (0)| | | 60 |00:00:00.01 | 25 | 4096 | 4096 | 4096 (0)| | 7 | PARTITION LIST SINGLE | | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 8 | TABLE ACCESS FULL | TEST_SAPFI_COICAR_AT5DAT11 | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 9 | PARTITION LIST ITERATOR | | 60 | 253 | 314 (1)| KEY | KEY | 8 |00:00:00.01 | 129 | | | | | * 10 | TABLE ACCESS FULL | TEST_DWF_SAPFI | 60 | 253 | 314 (1)| KEY | KEY | 8 |00:00:00.01 | 129 | | | | |- 11 | PARTITION LIST JOIN-FILTER| | 0 | 15197 | 314 (1)|:BF0000|:BF0000| 0 |00:00:00.01 | 0 | | | | |- 12 | TABLE ACCESS FULL | TEST_DWF_SAPFI | 0 | 15197 | 314 (1)|:BF0000|:BF0000| 0 |00:00:00.01 | 0 | | | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| Pstart| Pstop | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 329 (100)| | | 1 |00:00:00.01 | 154 | | | | | 1 | SORT AGGREGATE | | 1 | 1 | | | | 1 |00:00:00.01 | 154 | | | | | 2 | PART JOIN FILTER CREATE | :BF0000 | 1 | 38491 | 329 (1)| | | 8 |00:00:00.01 | 154 | | | | | 3 | NESTED LOOPS | | 1 | 38491 | 329 (1)| | | 8 |00:00:00.01 | 154 | | | | | 4 | SORT UNIQUE | | 1 | 152 | 13 (0)| | | 60 |00:00:00.01 | 25 | 4096 | 4096 | 4096 (0)| | 5 | PARTITION LIST SINGLE | | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 6 | TABLE ACCESS FULL | TEST_SAPFI_COICAR_AT5DAT11 | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 7 | PARTITION LIST ITERATOR| | 60 | 253 | 314 (1)| KEY | KEY | 8 |00:00:00.01 | 129 | | | | |* 8 | TABLE ACCESS FULL | TEST_DWF_SAPFI | 60 | 253 | 314 (1)| KEY | KEY | 8 |00:00:00.01 | 129 | | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Outline Data ------------- /*+ BEGIN_OUTLINE_DATA FULL(@"SEL$5DA710D3" "DWF"@"SEL$1") USE_NL(@"SEL$5DA710D3" "DWF"@"SEL$1") IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('19.1.0') DB_VERSION('19.1.0') ALL_ROWS OUTLINE_LEAF(@"SEL$5DA710D3") UNNEST(@"SEL$2") OUTLINE(@"SEL$1") OUTLINE(@"SEL$2") FULL(@"SEL$5DA710D3" "COI"@"SEL$2") LEADING(@"SEL$5DA710D3" "COI"@"SEL$2" "DWF"@"SEL$1") SEMI_TO_INNER(@"SEL$5DA710D3" "COI"@"SEL$2") END_OUTLINE_DATA */ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("DWF"."DATUMUCETNIPOM_CODE"=TO_NUMBER(TO_CHAR(INTERNAL_FUNCTION("COI"."DATUCT"),'yyyymmdd'))) 10 - filter("DWF"."DATUMUCETNIPOM_CODE"=TO_NUMBER(TO_CHAR(INTERNAL_FUNCTION("COI"."DATUCT"),'yyyymmdd'))) Hint Report (identified by operation id / Query Block Name / Object Alias): Total hints for statement: 1 (U - Unused (1)) --------------------------------------------------------------------------- 8 - SEL$5DA710D3 / COI@SEL$2 U - use_nl (coi) Note ----- - this is an adaptive plan (rows marked '-' are inactive)
Points to note here:
The really fascinating thing about this execution plan is that it contains a hint that was not used – but the plan changed from the default plan to a slightly more expensive plan.
There’s just one more surprise to reveal – we had an adaptive plan, which tends to mean the optimizer plays towards a nested loop join but hedges its bets to be able to swing to a hash join in mid-plan. This suggests that the real-time stats collector thought there wasn’t much data and a nested loop was good – but what happens when I run exactly the same query again? In my 12c system the answer was nothing changed, but in my 19c system a new plan appeared:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| Pstart| Pstop | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 331 (100)| | | 1 |00:00:00.01 | 154 | | | | | 1 | SORT AGGREGATE | | 1 | 1 | | | | 1 |00:00:00.01 | 154 | | | | |* 2 | HASH JOIN | | 1 | 120K| 331 (2)| | | 15197 |00:00:00.01 | 154 | 2171K| 2171K| 1636K (0)| | 3 | PART JOIN FILTER CREATE | :BF0000 | 1 | 15197 | 13 (0)| | | 60 |00:00:00.01 | 25 | | | | | 4 | SORT UNIQUE | | 1 | 15197 | 13 (0)| | | 60 |00:00:00.01 | 25 | 4096 | 4096 | 4096 (0)| | 5 | PARTITION LIST SINGLE | | 1 | 15197 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 6 | TABLE ACCESS FULL | TEST_SAPFI_COICAR_AT5DAT11 | 1 | 15197 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 7 | PARTITION LIST JOIN-FILTER| | 1 | 15197 | 314 (1)|:BF0000|:BF0000| 15197 |00:00:00.01 | 129 | | | | | 8 | TABLE ACCESS FULL | TEST_DWF_SAPFI | 60 | 15197 | 314 (1)|:BF0000|:BF0000| 15197 |00:00:00.01 | 129 | | | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('19.1.0') DB_VERSION('19.1.0') ALL_ROWS OUTLINE_LEAF(@"SEL$5DA710D3") UNNEST(@"SEL$2") OUTLINE(@"SEL$1") OUTLINE(@"SEL$2") FULL(@"SEL$5DA710D3" "COI"@"SEL$2") FULL(@"SEL$5DA710D3" "DWF"@"SEL$1") LEADING(@"SEL$5DA710D3" "COI"@"SEL$2" "DWF"@"SEL$1") USE_HASH(@"SEL$5DA710D3" "DWF"@"SEL$1") SEMI_TO_INNER(@"SEL$5DA710D3" "COI"@"SEL$2") END_OUTLINE_DATA */ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("DWF"."DATUMUCETNIPOM_CODE"=TO_NUMBER(TO_CHAR(INTERNAL_FUNCTION("COI"."DATUCT"),'yyyymmdd'))) Hint Report (identified by operation id / Query Block Name / Object Alias): Total hints for statement: 1 (U - Unused (1)) --------------------------------------------------------------------------- 6 - SEL$5DA710D3 / COI@SEL$2 U - use_nl (coi) Note ----- - statistics feedback used for this statement
This is the output with the ‘adaptive’ format in place – but the plan isn’t adaptive – the optimizer has used statistics feedback (formerly cardinality feedback)to work out a better plan. The hint is still unused of course but when we check the plan we can see that
Clearly there is a bug. It’s a slightly sensitive bug, and all I had to do to eliminate it was to gather stats on the underlying tables. (You’ll find in the table creation script at the end of this note that there are basically no object stats on the “big” partitioned table, which is presumably why the adaptive stuff came into play and allowed the bug to surface, and why 19c statistics feedback produced a new plan on the second execution)
It may be rather difficult for an outsider to pin down what’s going wrong and bypass the bug. One of the first ideas that appeared on the forum was that the Bloom filter pruning was breaking something – but when I added the hint /*+ opt_param(‘_bloom_pruning_enabled’,’false’) */ to the query all I got was basically the same nested loop plan without the Bloom filter creation and still ended up with the wrong result.
Finally, here’s a plan I got when I hinted query correctly to force the nested loop join with test_dwf_sapfi as the inner (second) table in the join (in other words I hinted the plan that had been giving me the wrong results):
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| Pstart| Pstop | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 405 (100)| | | 1 |00:00:00.01 | 154 | | | | | 1 | SORT AGGREGATE | | 1 | 1 | | | | 1 |00:00:00.01 | 154 | | | | | 2 | NESTED LOOPS | | 1 | 38491 | 405 (1)| | | 15197 |00:00:00.01 | 154 | | | | | 3 | SORT UNIQUE | | 1 | 152 | 13 (0)| | | 60 |00:00:00.01 | 25 | 4096 | 4096 | 4096 (0)| | 4 | PARTITION LIST SINGLE | | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 5 | TABLE ACCESS FULL | TEST_SAPFI_COICAR_AT5DAT11 | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 6 | PARTITION LIST ITERATOR| | 60 | 253 | 5 (0)| KEY | KEY | 15197 |00:00:00.01 | 129 | | | | |* 7 | TABLE ACCESS FULL | TEST_DWF_SAPFI | 60 | 253 | 5 (0)| KEY | KEY | 15197 |00:00:00.01 | 129 | | | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 7 - filter("DWF"."DATUMUCETNIPOM_CODE"=TO_NUMBER(TO_CHAR(INTERNAL_FUNCTION("COI"."DATUCT"),'yyyymmdd'))) Hint Report (identified by operation id / Query Block Name / Object Alias): Total hints for statement: 2 --------------------------------------------------------------------------- 1 - SEL$5DA710D3 - leading(@sel$5da710d3 coi@sel$2 dwf@sel$1) 7 - SEL$5DA710D3 / DWF@SEL$1 - use_nl(@sel$5da710d3 dwf@sel$1)
Compare this with the plan I got by using the wrong hint, resulting in the adaptive plan, but with Bloom filter pruning disable:
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| Pstart| Pstop | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 329 (100)| | | 1 |00:00:00.05 | 154 | | | | | 1 | SORT AGGREGATE | | 1 | 1 | | | | 1 |00:00:00.05 | 154 | | | | | 2 | NESTED LOOPS | | 1 | 38491 | 329 (1)| | | 8 |00:00:00.05 | 154 | | | | | 3 | SORT UNIQUE | | 1 | 152 | 13 (0)| | | 60 |00:00:00.01 | 25 | 4096 | 4096 | 4096 (0)| | 4 | PARTITION LIST SINGLE | | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 5 | TABLE ACCESS FULL | TEST_SAPFI_COICAR_AT5DAT11 | 1 | 152 | 13 (0)| 2 | 2 | 15197 |00:00:00.01 | 25 | | | | | 6 | PARTITION LIST ITERATOR| | 60 | 253 | 314 (1)| KEY | KEY | 8 |00:00:00.05 | 129 | | | | |* 7 | TABLE ACCESS FULL | TEST_DWF_SAPFI | 60 | 253 | 314 (1)| KEY | KEY | 8 |00:00:00.05 | 129 | | | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 7 - filter("DWF"."DATUMUCETNIPOM_CODE"=TO_NUMBER(TO_CHAR(INTERNAL_FUNCTION("COI"."DATUCT"),'yyyymmdd'))) Hint Report (identified by operation id / Query Block Name / Object Alias): Total hints for statement: 2 (U - Unused (1)) --------------------------------------------------------------------------- 0 - STATEMENT - opt_param('_bloom_pruning_enabled','false') 5 - SEL$5DA710D3 / COI@SEL$2 U - use_nl (coi)
It’s the same plan (with the same plan hash value though I haven’t shown that) – it has the same predicates, and does the same amount of work, But when the optimizer gets to this plan through the adaptive pathway the run-time engine produces the wrong results (note A-Rows = 8 at operation 2), while if the plan is forced by a correct set of hints the run-time engine produces the right path.
As you might guess, another way to bypass the problem was to disable adaptive plans – but when I did that the only way to get the nested loop path was through correct hinting anyway.
Here’s a script to create the test data:
rem rem Script: bloom_bug_02.sql rem Author: Michal Telensky / Jonathan Lewis rem Dated: Feb 2021 rem Purpose: rem rem Last tested rem 19.3.0.0 rem 12.2.0.1 rem rem See also: rem https://community.oracle.com/tech/developers/discussion/4480469/reproduc... rem https://livesql.oracle.com/apex/livesql/s/jzc2uyw6ecf2z2ul35nyrxelv rem drop table test_dwf_sapfi; drop table test_sapfi_coicar_at5dat11; purge recyclebin; -- -- Don't do this unless it's a private system -- Many sites seem to have the defaults anyway -- execute dbms_stats.delete_system_stats create table test_sapfi_coicar_at5dat11( datuct date, datumzprac number(8,0) ) row store compress advanced partition by list (datumzprac) ( partition p20000101 values (20000101) ) ; alter table test_sapfi_coicar_at5dat11 add partition p20200414 values (20200414); insert /*+ append */ into test_sapfi_coicar_at5dat11 select date'2019-11-20' datuct, 20200414 datumzprac from dual connect by level < 2 union all select date'2019-12-20' datuct, 20200414 datumzprac from dual connect by level < 2 union all select date'2019-12-29' datuct, 20200414 datumzprac from dual connect by level < 4 union all select date'2020-01-01' datuct, 20200414 datumzprac from dual connect by level < 55 union all select date'2020-01-08' datuct, 20200414 datumzprac from dual connect by level < 3 union all select date'2020-01-13' datuct, 20200414 datumzprac from dual connect by level < 8 union all select date'2020-01-14' datuct, 20200414 datumzprac from dual connect by level < 117 union all select date'2020-01-15' datuct, 20200414 datumzprac from dual connect by level < 65 union all select date'2020-01-30' datuct, 20200414 datumzprac from dual connect by level < 2 union all select date'2020-01-31' datuct, 20200414 datumzprac from dual connect by level < 12 union all select date'2020-02-01' datuct, 20200414 datumzprac from dual connect by level < 20 union all select date'2020-02-05' datuct, 20200414 datumzprac from dual connect by level < 4 union all select date'2020-02-10' datuct, 20200414 datumzprac from dual connect by level < 5 union all select date'2020-02-12' datuct, 20200414 datumzprac from dual connect by level < 2 union all select date'2020-02-17' datuct, 20200414 datumzprac from dual connect by level < 2 union all select date'2020-02-21' datuct, 20200414 datumzprac from dual connect by level < 16 union all select date'2020-02-29' datuct, 20200414 datumzprac from dual connect by level < 37 union all select date'2020-03-01' datuct, 20200414 datumzprac from dual connect by level < 1851 union all select date'2020-03-02' datuct, 20200414 datumzprac from dual connect by level < 227 union all select date'2020-03-03' datuct, 20200414 datumzprac from dual connect by level < 75 union all select date'2020-03-04' datuct, 20200414 datumzprac from dual connect by level < 19 union all select date'2020-03-05' datuct, 20200414 datumzprac from dual connect by level < 107 union all select date'2020-03-06' datuct, 20200414 datumzprac from dual connect by level < 163 union all select date'2020-03-07' datuct, 20200414 datumzprac from dual connect by level < 72 union all select date'2020-03-08' datuct, 20200414 datumzprac from dual connect by level < 78 union all select date'2020-03-09' datuct, 20200414 datumzprac from dual connect by level < 187 union all select date'2020-03-10' datuct, 20200414 datumzprac from dual connect by level < 124 union all select date'2020-03-11' datuct, 20200414 datumzprac from dual connect by level < 92 union all select date'2020-03-12' datuct, 20200414 datumzprac from dual connect by level < 137 union all select date'2020-03-13' datuct, 20200414 datumzprac from dual connect by level < 397 union all select date'2020-03-14' datuct, 20200414 datumzprac from dual connect by level < 52 union all select date'2020-03-15' datuct, 20200414 datumzprac from dual connect by level < 16 union all select date'2020-03-16' datuct, 20200414 datumzprac from dual connect by level < 622 union all select date'2020-03-17' datuct, 20200414 datumzprac from dual connect by level < 215 union all select date'2020-03-18' datuct, 20200414 datumzprac from dual connect by level < 299 union all select date'2020-03-19' datuct, 20200414 datumzprac from dual connect by level < 265 union all select date'2020-03-20' datuct, 20200414 datumzprac from dual connect by level < 627 union all select date'2020-03-21' datuct, 20200414 datumzprac from dual connect by level < 52 union all select date'2020-03-22' datuct, 20200414 datumzprac from dual connect by level < 60 union all select date'2020-03-23' datuct, 20200414 datumzprac from dual connect by level < 168 union all select date'2020-03-24' datuct, 20200414 datumzprac from dual connect by level < 255 union all select date'2020-03-25' datuct, 20200414 datumzprac from dual connect by level < 185 union all select date'2020-03-26' datuct, 20200414 datumzprac from dual connect by level < 240 union all select date'2020-03-27' datuct, 20200414 datumzprac from dual connect by level < 663 union all select date'2020-03-28' datuct, 20200414 datumzprac from dual connect by level < 88 union all select date'2020-03-29' datuct, 20200414 datumzprac from dual connect by level < 771 union all select date'2020-03-30' datuct, 20200414 datumzprac from dual connect by level < 328 union all select date'2020-03-31' datuct, 20200414 datumzprac from dual connect by level < 1675 union all select date'2020-04-01' datuct, 20200414 datumzprac from dual connect by level < 641 union all select date'2020-04-02' datuct, 20200414 datumzprac from dual connect by level < 251 union all select date'2020-04-03' datuct, 20200414 datumzprac from dual connect by level < 84 union all select date'2020-04-06' datuct, 20200414 datumzprac from dual connect by level < 325 union all select date'2020-04-07' datuct, 20200414 datumzprac from dual connect by level < 366 union all select date'2020-04-08' datuct, 20200414 datumzprac from dual connect by level < 459 union all select date'2020-04-09' datuct, 20200414 datumzprac from dual connect by level < 2470 union all select date'2020-04-10' datuct, 20200414 datumzprac from dual connect by level < 16 union all select date'2020-04-11' datuct, 20200414 datumzprac from dual connect by level < 16 union all select date'2020-04-12' datuct, 20200414 datumzprac from dual connect by level < 24 union all select date'2020-04-13' datuct, 20200414 datumzprac from dual connect by level < 130 union all select date'2020-04-14' datuct, 20200414 datumzprac from dual connect by level < 9 -- > change this value and the final (wrong) result changes in synch / commit / -- -- There are no indexes, so this method_opt collects fewer stats than expected -- No column stats on the partition(s), only partition row and block stats -- It does get basic column stats at the table level. -- declare schema_name varchar2(128); begin select sys_context('userenv', 'current_schema') into schema_name from dual; dbms_stats.gather_table_stats( ownname => schema_name, tabname => 'test_sapfi_coicar_at5dat11', partname => 'p20200414', estimate_percent => dbms_stats.auto_sample_size, method_opt => 'for all indexed columns size auto' ); end; / create table test_dwf_sapfi ( datumucetnipom_code number(8,0) not null enable ) row store compress advanced partition by list (datumucetnipom_code) ( partition p20000101 values (20000101) ) / begin for i in ( select distinct to_char(datuct, 'yyyymmdd') datumucetnipom_code from test_sapfi_coicar_at5dat11 order by 1 ) loop execute immediate 'alter table test_dwf_sapfi add partition p' || i.datumucetnipom_code || ' values (' || i.datumucetnipom_code || ')' ; end loop; end; / insert /*+ append */ into test_dwf_sapfi select to_number(to_char(datuct, 'yyyymmdd')) from test_sapfi_coicar_at5dat11 where datumzprac = 20200414 ; commit; -- -- The problems (seem to) go away if you collect stats -- -- execute dbms_stats.gather_table_stats(user,'test_dwf_sapfi',granularity=>'global') set serveroutput off set linesize 255 set pagesize 60 set trimspool on alter session set statistics_level='all'; prompt =================================== prompt plan with incorrect use_hash() hint prompt =================================== select /* use_hash(dwf) */ count(*) count_hash from test_dwf_sapfi dwf where exists ( select 1 from test_sapfi_coicar_at5dat11 coi where coi.datumzprac = 20200414 and to_char(coi.datuct,'yyyymmdd') = dwf.datumucetnipom_code ); select * from table(dbms_xplan.display_cursor(format=>'cost outline allstats last partition hint_report adaptive')); set serveroutput on spool off
Recent comments
3 years 5 weeks ago
3 years 17 weeks ago
3 years 21 weeks ago
3 years 22 weeks ago
3 years 27 weeks ago
3 years 48 weeks ago
4 years 16 weeks ago
4 years 46 weeks ago
5 years 30 weeks ago
5 years 30 weeks ago