By Franck Pachot
.
Do you know the optimizer_features_enable parameter? What do you think about it? Good or bad to use it?
If I tell you to set optimizer_features_enable parameter=11.2.0.4 when you upgrade to 12c, do you think it’s a very safe decision, or totally insane to upgrade and set behavior to previous version? It’s not an underscore parameter, you are allowed to use it.
Optimizer Features Enable
If you’re a developer, you know what is versioning. Every change (new feature or bug fix) you do to your software makes a new version of some part of the code. Those changes can be deployed individually as patches, grouped in patchset, or combined to build a new release. Which mean that you can compile an executable with exactly the set of features you want.
But you can do more. You can, instead of having different versions of source code, put everything into the same code, add a parameter to be able to enable the new code part or not, and you have a ‘if’ that checks the parameter in order to run the new code or the old one. You can do even more: when you deploy a new release, you set a runtime version parameter that enables all the features you want to deploy into your new release.
I know only one software that do that: the Oracle optimizer. It probably something hard to maintain for developers, but being able to choose at runtime the features you want to use is great and flexible.
Well in Oracle this idea is not only for the optimizer, you can also choose the compatible version for the database: store it compatible with a previous version. But I’m talking about the optimizer here.
Instance, Session, Statement
Being able to run the optimizer as of a previous version can be great, but it goes beyond that. You can change the optimizer_features_enable parameter only for your session if you want, and even only for one statement. For example:
SELECT /*+ optimizer_features_enable('11.2.0.4') */ ...
will optimize the query as it was optimized in the latest 11g patchset even if you are in 12c. And if you can’t change your queries, you can use SQL Patch to do that. Available in every edition.
Want to know which values you can put there?
There’s the quick way:
SQL> alter session set optimizer_features_enable=RBO;
ERROR:
ORA-00096: invalid value RBO for parameter optimizer_features_enable, must be from among 12.1.0.2, 12.1.0.1, 11.2.0.4, 11.2.0.3, 11.2.0.2, 11.2.0.1, 11.1.0.7, 11.1.0.6, 10.2.0.5, 10.2.0.4, 10.2.0.3, 10.2.0.2, 10.2.0.1, 10.1.0.5, 10.1.0.4, 10.1.0.3, 10.1.0, 9.2.0.8, 9.2.0, 9.0.1, 9.0.0, 8.1.7, 8.1.6, 8.1.5, 8.1.4, 8.1.3, 8.1.0, 8.0.7, 8.0.6, 8.0.5, 8.0.4, 8.0.3, 8.0.0
(Sorry for the joke about RBO – put whatever you want)
And the nice way:
SQL> select listagg(value,', ')within group(order by ordinal) from V$PARAMETER_VALID_VALUES where name='optimizer_features_enable';
LISTAGG(VALUE,',')WITHINGROUP(ORDERBYORDINAL)
----------------------------------------------------------------------------------------------------------------------------------------------
8.0.0, 8.0.3, 8.0.4, 8.0.5, 8.0.6, 8.0.7, 8.1.0, 8.1.3, 8.1.4, 8.1.5, 8.1.6, 8.1.7, 9.0.0, 9.0.1, 9.2.0, 9.2.0.8, 10.1.0, 10.1.0.3, 10.1.0.4, 10.1.0.5, 10.2.0.1, 10.2.0.2, 10.2.0.3, 10.2.0.4, 10.2.0.5, 11.1.0.6, 11.1.0.7, 11.2.0.1, 11.2.0.2, 11.2.0.3, 11.2.0.4, 12.1.0.1, 12.1.0.2
Is is bad or Good?
Well, the truth is that I find that very god to be able to do that, but I’m always reluctant to recommend them because I like to learn and use new features, and I find that setting OFE is negative and old-fashioned. Actually, I’ve that double feeling because there are always two different contexts. Actually this is the reason of that blog: clear out that ‘negative’ feeling about OFE.
New project
You are starting a new project, building a new application? Then install the latest database version and use the latest features. There are a lot of new features that will give more performance, more flexibility, more stability to your application, so use them. No OFE setting here except if you find a bug and need to workaround before getting the patch. But even there, you will not set OFE to previous version. You will disable only the feature or fix controls that cause the problem.
Migration
In the opposite, you are only migrating an existing application that has been tuned on a previous version of the database and you don’t have the budget to involve development in new testing and tuning? Then take the safe way. Set Optimizer Features to the previous version and everything will be fine. You build new reports on that application? Then use new features for them. You can set it for the session. Why not having it set in a logon trigger that check the service name?
Basically, OFE helps to:
- Sort out any other migration issue before having to address the execution plan change ones.
- Test new plans in a managed way. Do it when you are available to run non-regression tests. You can even use SQL Performance Analyzer if you have Tuning Pack.
- You can also capture SQL Plan Baselines while OFE is set to old version, and then bring it back to current version. Then you will evolve plans only when there is no regression in response time. SPM is available in Enterprise Edition without any option.
How long?
Of course, it’s not because you can set optimizer to 8.0 version that it’s good to do it in 12c. OFE helps to postpone the upgrade of the optimizer so that you don’t have to test and resolve everything at the same time. But you should keep OFE to previous version only for a few months or year. Donc cumulate the gaps on multiple releases.
Take the occasion of an application release, when lot of non-regression testing will be done anyway, to bring OFE to latest version. Then you will see lot of statements improved (as it’s the goal of most of new features) and a few issues that will have to be addressed. You may have to gather statistics differently, to write some statements differently, to get rid of lot of old profiles and maybe implement a few new ones, etc. And the you will have a optimal application with its latest version running with the latest optimizer improvements.
Maybe you will choose to disable some features. But you probably don’t need to disable all new features. Let’s take an example about SQL Plan Directives that brought a lot of instability in 12c migrations. You have several ways to disable some of their behaviour (see this blog post). Maybe you will do that until 12.2 that will fix a lot of issues for sure. But don’t disable all 12c features. Don’t disable all adaptive features. Adaptive Plans are great and brings stability by avoiding bad plans to run for hours.
Features per version
When I see that an issue is fixed an issue by setting OFE to a previous version, I try to find which feature is responsible for the problem. I’ve a small script that parses a query with OFE set to previous versions and check (from event 10132 trace) the changes on documented and undocumented parameters. Here are those for the latest patchsets.
_bloom_serial_filter = on new in 11.2.0.4 was = off enable serial bloom filter on exadata (QKSFM_EXECUTION - SQL EXECUTION)
_fix_control_key = 1167487983 new in 11.2.0.4 was = -726982239
optimizer_features_enable = 11.2.0.4 new in 11.2.0.4 was = 11.2.0.3 optimizer plan compatibility parameter (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_undo_cost_change = 11.2.0.4 new in 11.2.0.4 was = 11.2.0.3 optimizer undo cost change (QKSFM_CBO - SQL Cost Based Optimization)
> _px_scalable_invdist = false
_px_scalable_invdist = true _optimizer_adaptive_plans = false
_optimizer_adaptive_plans = true < enable adaptive plans (QKSFM_ADAPTIVE_PLAN - Adaptive plans)
_optimizer_ansi_join_lateral_enhance = true new in 12.1.0.1 was = false optimization of left/full ansi-joins and lateral views (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_ansi_rearchitecture = true new in 12.1.0.1 was = false re-architecture of ANSI left, right, and full outer joins (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_batch_table_access_by_rowid = true new in 12.1.0.1 was = false enable table access by ROWID IO batching (QKSFM_ALL - A Universal Feature)
_optimizer_cluster_by_rowid = true new in 12.1.0.1 was = false enable/disable the cluster by rowid feature (QKSFM_CLUSTER_BY_ROWID - Cluster By Rowid Transformation)
_optimizer_cube_join_enabled = true new in 12.1.0.1 was = false enable cube join (QKSFM_JOIN_METHOD - Join methods)
_optimizer_dsdir_usage_control = 126 new in 12.1.0.1 was = 0 controls optimizer usage of dynamic sampling directives (QKSFM_CBO - SQL Cost Based Optimization)
optimizer_features_enable = 12.1.0.1 new in 12.1.0.1 was = 11.2.0.4 optimizer plan compatibility parameter (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_gather_stats_on_load = true new in 12.1.0.1 was = false enable/disable online statistics gathering (QKSFM_STATS - Optimizer statistics)
_optimizer_hybrid_fpwj_enabled = true new in 12.1.0.1 was = false enable hybrid full partition-wise join when TRUE (QKSFM_PQ - Parallel Query)
_optimizer_multi_table_outerjoin = true new in 12.1.0.1 was = false allows multiple tables on the left of outerjoin (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_nlj_hj_adaptive_join = true new in 12.1.0.1 was = false allow adaptive NL Hash joins (QKSFM_ADAPTIVE_PLAN - Adaptive plans)
_optimizer_null_accepting_semijoin = true new in 12.1.0.1 was = false enables null-accepting semijoin (QKSFM_TRANSFORMATION - Query Transformation)
_optimizer_partial_join_eval = true new in 12.1.0.1 was = false partial join evaluation parameter (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_proc_rate_level = basic new in 12.1.0.1 was = off control the level of processing rates (QKSFM_STATS - Optimizer statistics)
_optimizer_strans_adaptive_pruning = true new in 12.1.0.1 was = false allow adaptive pruning of star transformation bitmap trees (QKSFM_STAR_TRANS - Star Transformation)
_optimizer_undo_cost_change = 12.1.0.1 new in 12.1.0.1 was = 11.2.0.4 optimizer undo cost change (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_unnest_scalar_sq = true new in 12.1.0.1 was = false enables unnesting of of scalar subquery (QKSFM_TRANSFORMATION - Query Transformation)
_optimizer_use_gtt_session_stats = true new in 12.1.0.1 was = false use GTT session private statistics (QKSFM_STATS - Optimizer statistics)
_px_adaptive_dist_method = choose new in 12.1.0.1 was = off determines the behavior of adaptive distribution methods (QKSFM_PQ - Parallel Query)
_px_concurrent = true new in 12.1.0.1 was = false enables pq with concurrent execution of serial inputs (QKSFM_PQ - Parallel Query)
_px_cpu_autodop_enabled = true new in 12.1.0.1 was = false enables or disables auto dop cpu computation (QKSFM_PQ - Parallel Query)
_px_filter_parallelized = true new in 12.1.0.1 was = false enables or disables correlated filter parallelization (QKSFM_PQ - Parallel Query)
_px_filter_skew_handling = true new in 12.1.0.1 was = false enable correlated filter parallelization to handle skew (QKSFM_PQ - Parallel Query)
_px_groupby_pushdown = force new in 12.1.0.1 was = choose perform group-by pushdown for parallel query (QKSFM_PQ - Parallel Query)
_px_join_skew_handling = true new in 12.1.0.1 was = false enables skew handling for parallel joins (QKSFM_PQ - Parallel Query)
_px_object_sampling = 1 new in 12.1.0.1 was = 0 parallel query sampling for base objects (100000 = 100%) (QKSFM_PQ - Parallel Query)
_px_object_sampling_enabled = true new in 12.1.0.1 was = false use base object sampling when possible for range distribution (QKSFM_PQ - Parallel Query)
_px_parallelize_expression = true new in 12.1.0.1 was = false enables or disables expression evaluation parallelization (QKSFM_PQ - Parallel Query)
_px_partial_rollup_pushdown = adaptive new in 12.1.0.1 was = off perform partial rollup pushdown for parallel execution (QKSFM_PQ - Parallel Query)
_px_replication_enabled = true new in 12.1.0.1 was = false enables or disables replication of small table scans (QKSFM_PQ - Parallel Query)
_px_single_server_enabled = true new in 12.1.0.1 was = false allow single-slave dfo in parallel query (QKSFM_PQ - Parallel Query)
_px_wif_dfo_declumping = choose new in 12.1.0.1 was = off NDV-aware DFO clumping of multiple window sorts (QKSFM_PQ - Parallel Query)
_px_wif_extend_distribution_keys = true new in 12.1.0.1 was = false extend TQ data redistribution keys for window functions (QKSFM_PQ - Parallel Query)
_distinct_agg_optimization_gsets = choose new in 12.1.0.2 was = off Use Distinct Aggregate Optimization for Grouping Sets (QKSFM_ALL - A Universal Feature)
_fix_control_key = -1261475868 new in 12.1.0.2 was = 890546215
_gby_vector_aggregation_enabled = true new in 12.1.0.2 was = false enable group-by and aggregation using vector scheme (QKSFM_TRANSFORMATION - Query Transformation)
_optimizer_aggr_groupby_elim = true new in 12.1.0.2 was = false group-by and aggregation elimination (QKSFM_TRANSFORMATION - Query Transformation)
_optimizer_cluster_by_rowid_batched = true new in 12.1.0.2 was = false enable/disable the cluster by rowid batching feature (QKSFM_CLUSTER_BY_ROWID - Cluster By Rowid Transformation)
_optimizer_cluster_by_rowid_control = 129 new in 12.1.0.2 was = 3 internal control for cluster by rowid feature mode (QKSFM_CLUSTER_BY_ROWID - Cluster By Rowid Transformation)
optimizer_features_enable = 12.1.0.2 new in 12.1.0.2 was = 12.1.0.1 optimizer plan compatibility parameter (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_inmemory_access_path = true new in 12.1.0.2 was = false optimizer access path costing for in-memory (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_inmemory_autodop = true new in 12.1.0.2 was = false optimizer autoDOP costing for in-memory (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_inmemory_bloom_filter = true new in 12.1.0.2 was = false controls serial bloom filter for in-memory tables (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_inmemory_cluster_aware_dop = true new in 12.1.0.2 was = false Affinitize DOP for inmemory objects (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_inmemory_gen_pushable_preds = true new in 12.1.0.2 was = false optimizer generate pushable predicates for in-memory (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_inmemory_minmax_pruning = true new in 12.1.0.2 was = false controls use of min/max pruning for costing in-memory tables (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_inmemory_table_expansion = true new in 12.1.0.2 was = false optimizer in-memory awareness for table expansion (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_reduce_groupby_key = true new in 12.1.0.2 was = false group-by key reduction (QKSFM_TRANSFORMATION - Query Transformation)
_optimizer_undo_cost_change = 12.1.0.2 new in 12.1.0.2 was = 12.1.0.1 optimizer undo cost change (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_vector_transformation = true new in 12.1.0.2 was = false perform vector transform (QKSFM_VECTOR_AGG - Vector Transformation)
_px_external_table_default_stats = true new in 12.1.0.2 was = false the external table default stats collection enable/disable (QKSFM_PQ - Parallel Query)
_ds_enable_view_sampling = true new in 12.1.0.2.1 was = false Use sampling for views in Dynamic Sampling (QKSFM_DYNAMIC_SAMPLING - Dynamic sampling)
_ds_sampling_method = PROGRESSIVE new in 12.1.0.2.1 was = NO_QUALITY_METRIC Dynamic sampling method used (QKSFM_DYNAMIC_SAMPLING - Dynamic sampling)
_ds_xt_split_count = 1 new in 12.1.0.2.1 was = 0 Dynamic Sampling Service: split count for external tables (QKSFM_DYNAMIC_SAMPLING - Dynamic sampling)
_fix_control_key = 0 new in 12.1.0.2.1 was = -1261475868
_key_vector_create_pushdown_threshold = 20000 new in 12.1.0.2.1 was = 0 minimum grouping keys for key vector create pushdown (QKSFM_VECTOR_AGG - Vector Transformation)
_optimizer_ads_use_partial_results = true new in 12.1.0.2.1 was = false Use partial results of ADS queries (QKSFM_DYNAMIC_SAMPLING - Dynamic sampling)
_optimizer_ads_use_spd_cache = true new in 12.1.0.2.1 was = false use Sql Plan Directives for caching ADS queries (QKSFM_DYNAMIC_SAMPLING - Dynamic sampling)
_optimizer_band_join_aware = true new in 12.1.0.2.1 was = false enable the detection of band join by the optimizer (QKSFM_ALL - A Universal Feature)
_optimizer_bushy_join = on new in 12.1.0.2.1 was = off enables bushy join (QKSFM_BUSHY_JOIN - bushy join)
_optimizer_cbqt_or_expansion = on new in 12.1.0.2.1 was = off enables cost based OR expansion (QKSFM_CBQT_OR_EXPANSION - Cost Based OR Expansion)
_optimizer_eliminate_subquery = true new in 12.1.0.2.1 was = false consider elimination of subquery optimization (QKSFM_ELIMINATE_SQ - eliminate subqueries)
_optimizer_enable_plsql_stats = true new in 12.1.0.2.1 was = false Use statistics of plsql functions (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_enhanced_join_elimination = true new in 12.1.0.2.1 was = false Enhanced(12.2) join elimination (QKSFM_TABLE_ELIM - Table Elimination)
optimizer_features_enable = 12.2.0.1 new in 12.1.0.2.1 was = 12.1.0.2 optimizer plan compatibility parameter (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_inmemory_use_stored_stats = AUTO new in 12.1.0.2.1 was = NEVER optimizer use stored statistics for in-memory tables (QKSFM_ALL - A Universal Feature)
_optimizer_key_vector_pruning_enabled = true new in 12.1.0.2.1 was = false enables or disables key vector partition pruning (QKSFM_VECTOR_AGG - Vector Transformation)
_optimizer_multicol_join_elimination = true new in 12.1.0.2.1 was = false eliminate multi-column key based joins (QKSFM_TABLE_ELIM - Table Elimination)
_optimizer_undo_cost_change = 12.2.0.1 new in 12.1.0.2.1 was = 12.1.0.2 optimizer undo cost change (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_union_all_gsets = true new in 12.1.0.2.1 was = false Use Union All Optimization for Grouping Sets (QKSFM_GROUPING_SET_XFORM - Grouping Set Transformation)
_optimizer_use_table_scanrate = HADOOP_ONLY new in 12.1.0.2.1 was = OFF Use Table Specific Scan Rate (QKSFM_CBO - SQL Cost Based Optimization)
_optimizer_use_xt_rowid = true new in 12.1.0.2.1 was = false Use external table rowid (QKSFM_TRANSFORMATION - Query Transformation)
_optimizer_vector_base_dim_fact_factor = 200 new in 12.1.0.2.1 was = 0 cost based vector transform base dimension to base fact ratio (QKSFM_VECTOR_AGG - Vector Transformation)
_pwise_distinct_enabled = true new in 12.1.0.2.1 was = false enable partition wise distinct (QKSFM_PARTITION - Partition)
_px_dist_agg_partial_rollup_pushdown = adaptive new in 12.1.0.2.1 was = off perform distinct agg partial rollup pushdown for px execution (QKSFM_PQ - Parallel Query)
_px_scalable_invdist_mcol = true new in 12.1.0.2.1 was = false enable/disable px plan for percentile functions on multiple columns (QKSFM_PQ - Parallel Query)
_query_rewrite_use_on_query_computation = true new in 12.1.0.2.1 was = false query rewrite use on query computation (QKSFM_TRANSFORMATION - Query Transformation)
_recursive_with_branch_iterations = 7 new in 12.1.0.2.1 was = 1 Expected number of iterations of the recurive branch of RW/CBY (QKSFM_EXECUTION - SQL EXECUTION)
_recursive_with_parallel = true new in 12.1.0.2.1 was = false Enable/disable parallelization of Recursive With (QKSFM_EXECUTION - SQL EXECUTION)
_sqlexec_hash_based_distagg_ssf_enabled = true new in 12.1.0.2.1 was = false enable hash based distinct aggregation for single set gby queries (QKSFM_EXECUTION - SQL EXECUTION)
_vector_encoding_mode = manual new in 12.1.0.2.1 was = off enable vector encoding(OFF/MANUAL/AUTO) (QKSFM_EXECUTION - SQL EXECUTION)
_xt_sampling_scan_granules = on new in 12.1.0.2.1 was = off Granule Sampling for Block Sampling of External Tables (QKSFM_EXECUTION - SQL EXECUTION)
Conclusion
- It’s not fool to use new version of optimizer for new projects
- It’s not bad to use previous optimizer version if your application has been tuned for that
- It’s good to try to use new optimizer version when testing a new application release