Skip to Main Content

Oracle Database Discussions

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

SQL patch (or profile force_match) on a system query produced by a refresh mview

Hi,
I migrate databases 12c to 19c. One database have hundred thousands objects. A dbms_mview.refresh produce this query that is very slow on this database.
sql_id 091fb1shwqyn8
select o.owner#, o.name, o.namespace, o.obj#, d.d_timestamp, nvl(d.property,0), o.type#, o.subname, d.d_attrs from dependency$ d, obj$ o where d.p_obj#=:1 and (d.p_timestamp=nvl(:2, d.p_timestamp) or d.property=2) and o.owner#=nvl(:3,o.owner#) and d.d_obj#=o.obj# order by o.obj#
With the sql_id I created a sql patch (or sql profile force_match) to inject the hint opt_param('_optimizer_push_pred_cost_based','false').
I execute the select and the plan note says that the sql patch (or profile) is used and the select is fast.
When I run the refresh view, the sql (sql_id 091fb1shwqyn8) is run implicitly by the refresh view, but the sql patch is not used !
Does sql patch is supposed to works in this kind of execution (system query execute implicitly by a refresh view) ?
Thanks a lot.

This post has been answered by stephane_parenteau on Mar 29 2021
Jump to Answer

Comments

Mohamed Houri

If you don’t see, at the bottom of the corresponding execution plan, a Note saying that the SQL profile or SQL patch has been used then this means that the force_matching_signature of the generated recursive query is not equal to the signature of the SQL Patch (SQL Profile)
That’s said I don’t see why a recursive query will refuse to use a SQL Profile just because it is recursively generated. It should react exactly as would react any other user sql_id. I have, though, rarely had to fix a SQL profile on a recursive query
Best regards
Mohamed

user9540031

Actually, that SQL patch works as advertised (I have tried it on a test DB) on that specific SQL id 091fb1shwqyn8... But apparently, it works only when that query is called as user-level SQL, not when it is run as recursive SQL.
(Remark: it's not a problem of SQL matching signature, even though dbms_sqldiag.create_sql_patch will only create SQL patches with FORCE_MATCHING = 'NO'. Here there is no difficulty in reproducing the exact SQL id.)
Hypothesis: could this query be executed in low-level code, where SQL patches would simply be ignored?
@stephane-parenteau:

  1. How bad is the issue? Could you please share details about the plan and query performance? Have dictionary statistics (dbms_stats.gather_dictionary_statistics) been gathered recently?
    (Remark: I have seen irritatingly slow data dictionaries, even with fresh statistics, on DBs with hundreds of thousands of subpartitions, but not to such an extent of having to fix low-level recursive queries like that. I mean, the idea came to mind a few times, but in the end we could live with it, these were not severe or blocking issues.)
    And 2) how is opt_param('_optimizer_push_pred_cost_based','false') going to fix it? Again, could you please share the resulting plan and query performance figures? Thanks!
    Regards,
stephane_parenteau

Hi,
When I saw the performance problem, I ran the session with tkprof to discovered the bad sql (and sql_id) during the dbms_mview.refresh(out_of_place). Here is the trace of the sql.
SQL ID: 091fb1shwqyn8 Plan Hash: 2505069670
select o.owner#, o.name, o.namespace, o.obj#, d.d_timestamp,
nvl(d.property,0), o.type#, o.subname, d.d_attrs
from
dependency$ d, obj$ o where d.p_obj#=:1 and (d.p_timestamp=nvl(:2,
d.p_timestamp) or d.property=2) and o.owner#=nvl(:3,o.owner#) and
d.d_obj#=o.obj# order by o.obj#
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 356 0.01 0.01 0 0 0 0
Execute 711 0.41 0.41 0 0 0 0
Fetch 1066 2887.28 2892.07 509 10219610 0 355
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2133 2887.71 2892.50 509 10219610 0 355
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
0 118 355 SORT ORDER BY (cr=14495 pr=111 pw=0 time=4206796 us starts=1 cost=15 size=231 card=1)
0 118 355 HASH JOIN (cr=14495 pr=111 pw=0 time=4267508 us starts=1 cost=14 size=231 card=1)
2006485 2006485 2006485 NESTED LOOPS (cr=14370 pr=0 pw=0 time=3559117 us starts=1 cost=14 size=231 card=1)
2006485 2006485 2006485 NESTED LOOPS (cr=14370 pr=0 pw=0 time=3213777 us starts=1 cost=14 size=231 card=3)
2006485 2006485 2006485 STATISTICS COLLECTOR (cr=14370 pr=0 pw=0 time=2855170 us starts=1)
2006485 2006485 2006485 VIEW VW_JF_SET$DDE30DF4 (cr=14370 pr=0 pw=0 time=2455015 us starts=1 cost=5 size=591 card=3)
2006485 2006485 2006485 UNION-ALL (cr=14370 pr=0 pw=0 time=1889478 us starts=1)
2006485 2006485 2006485 FILTER (cr=14370 pr=0 pw=0 time=888877 us starts=1)
2006485 2006485 2006485 INDEX FAST FULL SCAN I_OBJ2 (cr=14370 pr=0 pw=0 time=425396 us starts=1 cost=2 size=41 card=1)(object id 6000040)
0 0 0 FILTER (cr=0 pr=0 pw=0 time=4 us starts=1)
0 0 0 INDEX RANGE SCAN I_OBJ2 (cr=0 pr=0 pw=0 time=0 us starts=0 cost=3 size=82 card=2)(object id 6000040)
0 0 0 INDEX RANGE SCAN I_DEPENDENCY1 (cr=0 pr=0 pw=0 time=0 us starts=0 cost=2 size=0 card=1)(object id 106)
0 0 0 TABLE ACCESS BY INDEX ROWID DEPENDENCY$ (cr=0 pr=0 pw=0 time=0 us starts=0 cost=3 size=34 card=1)
0 118 355 TABLE ACCESS BY INDEX ROWID BATCHED DEPENDENCY$ (cr=125 pr=111 pw=0 time=1369 us starts=1 cost=3 size=34 card=1)
0 118 355 INDEX RANGE SCAN I_DEPENDENCY2 (cr=3 pr=1 pw=0 time=946 us starts=1 cost=2 size=0 card=1)(object id 107)
Yes I gathered the dict stats.
dbms_stats.gather_dictionary_stats(cascade => true, no_invalidate => false, options => 'GATHER', degree => 5);
I also gathered directly on sys tables, but the xplan and performance are bad also :
execute dbms_stats.gather_table_stats(ownname => 'SYS', tabname => 'DEPENDENCY$', estimate_percent => dbms_stats.auto_sample_size, cascade => true, no_invalidate => false, options => 'GATHER', degree => 5);
execute dbms_stats.gather_table_stats(ownname => 'SYS', tabname => 'OBJ$', estimate_percent => dbms_stats.auto_sample_size, cascade => true, no_invalidate => false, options => 'GATHER', degree => 5);
If I gathered on DEPENDENCY$ and deleted stat on OBJ$, the xplan and performance are very fast. But like we know it's not recommended and I don't want no stats on OBJ$ ! :
execute dbms_stats.gather_table_stats(ownname => 'SYS', tabname => 'DEPENDENCY$', estimate_percent => dbms_stats.auto_sample_size, cascade => true, no_invalidate => false, options => 'GATHER', degree => 5);
execute dbms_stats.delete_table_stats(ownname => 'SYS', tabname => 'OBJ$');
It's not my first time also I saw bad performance on low-level recursive queries. Exemple on database 12c I have had to use _fix_control parameter (recommended from Oracle SR).
When I have this king of performance problem with low-level recursive queries, I search with predicate to find articles about this. Here I search the UNION-ALL and it's why I found the _optimizer_push_pred_cost_based in these articles.
SQL with 'VIEW PUSH PREDICATE' in 12.2 Causing Performance Issue (Doc ID 2641737.1)
Bug 29867728 - UNION ALL PUSHED PREDICATE Is Chosen On 19c When UNION-ALL Plan May Have Less Cost (Doc ID 29867728.8)
https://community.oracle.com/mosc/discussion/4081452/optimizer-push-pred-cost-based-and-or-sql-patch
With _optimizer_push_pred_cost_based=false, the xplan and performance are very fast (like it was on database 12c).
SQL Plan Monitoring Details (Plan Hash Value=450768487)
========================================================================
| Id | Operation | Name |
| | | |
========================================================================
| 0 | SELECT STATEMENT | |
| 1 | SORT ORDER BY | |
| 2 | NESTED LOOPS | |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED | DEPENDENCY$ |
| 4 | INDEX RANGE SCAN | I_DEPENDENCY2 |
| 5 | VIEW | VW_JF_SET$DDE30DF4 |
| 6 | UNION-ALL PARTITION | |
| 7 | FILTER | |
| 8 | TABLE ACCESS BY INDEX ROWID BATCHED | OBJ$ |
| 9 | INDEX RANGE SCAN | I_OBJ1 |
| 10 | FILTER | |
| 11 | TABLE ACCESS BY INDEX ROWID BATCHED | OBJ$ |
| 12 | INDEX RANGE SCAN | I_OBJ1 |
========================================================================
SQL_ID EXECUTIONS BGET BGET_BY_EXEC CPU_BY_EXEC ELAPSED_BY_EXEC
------------- ---------- ---------- ------------ ----------- ---------------
091fb1shwqyn8 359 1113 3 .0001 .0001
If it's not possible to sql patch a low-level recursive queries, instead I will modify the job that executes all the 19c dbms_mview.refresh and this job will execute fastly.
alter session set "_optimizer_push_pred_cost_based"=false;
Thanks.

user9540031

Oh what a depressing sight! That plan is terrible! (But thanks for sharing the details!)
Everything seems wrong in that plan: wrong join order, and wrong cost estimate for that index FFS on I_OBJ2 to begin with (cost=2). This is so much lower than the actual number of logical reads (cr=14370); any idea about why?
Reminds me of these notes from Jonathan Lewis' blog: https://jonathanlewis.wordpress.com/?s=index_ffs+cost, but here the discrepancy seems just enormous.
Regards,

Jonathan Lewis

Since you're on 19c you can pull the plan from memory with the full "hint report", and the "Outline Information". The latter might give you some idea of why the optimizer could apply your hint and still come up with a different plan. Remember that an SQL Plan Baseline (if generated by Oracle) tends to be a long and complex list of hints - a single hint (whether hacked into place as an SQL Profile, Patch of Baseline) to disable one feature is by no means guaranteed to give you the same plan in one system as it did in another.
I've just pulled that SQL_ID from memory on my 19.3 system, and the thing that stands out in the Outline Information is the hint: OPT_PARAM('_optim_peek_user_binds' 'false'), which is not something I've set up, so perhaps it's a session setting that is invoked by the dbms_mview.refresh() procedure that results in the optimizer looking at lots more execution plans using completely different arithmetic from what it does in your test.
Another thing you could do to get some clues is to try executing the query from a foreground session to see if you get your desired plan, then invoke the refresh again to force the background execution, then query v$sql_shared_cursor - because if you get a different execution plan you should get a new child cursor - and that might tell you what's difference about the two environments.

set long 20000
select child_number, con_id, reason from V$sql_shared_cursor where sql_id = '091fb1shwqyn8';

Regards
Jonathan Lewis

stephane_parenteau
Answer

Hi,
Since my first post, I moved forward with the configuration of the CBO 19c (reading, testing, calibrating, etc). The application that I'm migrating is a mission critical app with about 30000 thousands SQL.
During these works many of SQL have poor performance in the application and these SQL have similar pattern (explain plan "union-all" instead of "concatenation").
I found that in the "or-expansions algorithm" some new optimizations have been introduced since 12.2+.
So the main cause for these SQL (including the system query of my first post) is the new "or-expansions algorithm 12.2+" and the solution is to set the parameter _optimizer_cbqt_or_expansion=OFF.
Here is some articles about this change.
Bug 27541468 - Poor Query Performance With CBQT OR Exapansion (Doc ID 27541468.8)
After Upgrade to 12.2 OR Expansion is Unexpectedly Bypassed for Some SQL Queries Which Can Result in Sub-optimal Execution Plans (Doc ID 2279072.1)
Bug 26019148 - cbqt ore does not apply to correlated scalar subquery with oe (Doc ID 26019148.8)
https://stackoverflow.com/questions/55075173/orcale-behavior-with-left-outer-join-with-or-condition
https://blog.pythian.com/debugging-cbqt-expansion-10053-trace/
And FYI, during my works with CBO 19c, I found also many of others SQL have poor performance. In this case the problem comes from the system stats MREADTIM, MBRC, SREADTIM.
That is to say in 19c+ the "cpu cost model algorithm" have been changed. The solutions is to adjust these system stats or configure the database parameter _fix_control 27643128.
Here is some articles about this change.
Optimizer Chooses Expensive Index Full Scan over Index Fast Full Scan or Full Table Scan from 12.1 (Doc ID 2382922.1).
https://blog.dbi-services.com/a-change-in-full-table-scan-costs-in-19c/.
Thanks.

Marked as Answer by stephane_parenteau · Mar 29 2021
1 - 6

Post Details

Added on Feb 1 2021
6 comments
1,027 views