diff --git a/app/controllers/dba_history_controller.rb b/app/controllers/dba_history_controller.rb index 2a663e11..0cc262ca 100644 --- a/app/controllers/dba_history_controller.rb +++ b/app/controllers/dba_history_controller.rb @@ -2186,7 +2186,7 @@ def generate_baseline_creation snap_corrected_warning = '' if min_snap_id == max_snap_id min_snap_id -= 1 - snap_corrected_warning = "\n-- End snapshot ID (#{max_snap_id}) must be greater than begin snapshot ID ((#{max_snap_id}).\nTherfore begin snapshot ID has been adjusted to #{min_snap_id}!\n\n" + snap_corrected_warning = "\n-- End snapshot ID (#{max_snap_id}) must be greater than begin snapshot ID ((#{max_snap_id}).\n-- Therfore begin snapshot ID has been adjusted to #{min_snap_id}!\n\n" end dbms_sqltune = get_db_version >= '18' ? 'DBMS_SQLSET' : 'DBMS_SQLTUNE' # DBMS_SQLSET contains similar functions like DBMS_SQLTUNE but without requiring Tuning Pack @@ -2223,7 +2223,7 @@ def generate_baseline_creation END LOOP; -- Create new SQL Tuning Set (STS) - DBMS_SQLTUNE.CREATE_SQLSET(sqlset_name => '#{sts_name}', description => 'Panorama: SQL Tuning Set for loading plan into SQL Plan Baseline'); + #{dbms_sqltune}.CREATE_SQLSET(sqlset_name => '#{sts_name}', description => 'Panorama: SQL Tuning Set for loading plan into SQL Plan Baseline'); -- Populate STS from AWR, using a time duration when the desired plan was used -- Specify the sql_id in the basic_filter (other predicates are available, see documentation) diff --git a/app/controllers/dba_sga_controller.rb b/app/controllers/dba_sga_controller.rb index 765fff6b..f0bca76a 100644 --- a/app/controllers/dba_sga_controller.rb +++ b/app/controllers/dba_sga_controller.rb @@ -1877,44 +1877,15 @@ def list_dbms_xplan_display_multiple_children # Show possibilities to influence the sql plan def influence_sql_plan - @sql_id = params[:sql_id] - @user_name = params[:user_name] - @min_snap_id = params[:min_snap_id] # only set if called from DBA_Hist_SQLStat view - @max_snap_id = params[:max_snap_id] # only set if called from DBA_Hist_SQLStat view + @sql_id = prepare_param :sql_id + @user_name = prepare_param :user_name + @min_snap_id = prepare_param :min_snap_id # only set if called from DBA_Hist_SQLStat view + @max_snap_id = prepare_param :max_snap_id # only set if called from DBA_Hist_SQLStat view @dbid = prepare_param_dbid # only set if called from DBA_Hist_SQLStat view - @force_matching_signature = params[:force_matching_signature] - @exact_matching_signature = params[:exact_matching_signature] + @force_matching_signature = prepare_param :force_matching_signature + @exact_matching_signature = prepare_param :exact_matching_signature + @plan_hash_value = prepare_param :plan_hash_value # only set if called from SGA view with unique plan hash value - @methods = [] - - @methods << { type: :sql_tuning_advisor, - description: "Run Oracle's builtin SQL Tuning Advisor for this SQL to automatically find a better execution plan.\n\nADVISOR privilege is needed for the user to run the SQL Tuning Advisor.\nCREATE ANY SQL PROFILE privilege is needed to create a SQL profile from the result of the Tuning Advisor.", - option_pack_needed: "Enterprise Edition + Tuning Pack" - } - - @methods << { type: :plan_baseline, - description: "Generate script to fix exactly one execution plan as SQL-baseline for this SQL.#{"\nYou may try to load SQLplan baseline from cursor cache instead (from current SGA)." if PanoramaConnection.edition == :standard || PanoramaConnection.management_pack_license != :diagnostics_and_tuning_pack}", - option_pack_needed: "Enterprise Edition + #{ get_db_version < '18' ? "Tuning Pack" : "Diagnostics Pack"}" - } - - @methods << { type: :sql_profile, - description: "Generates commands for manual creation of a SQL profile.\nThis allows to inject your own defined optimizer hints to the SQL.", - option_pack_needed: "Enterprise Edition + Tuning Pack" - } - - @methods << { type: :sql_patch, - description: "Generates commands for creation of a SQL patch.\nThis allows to inject your own defined optimizer hints to the SQL.\nSimilar to SQL profile, but without the need for licensed Tuning Pack.", - option_pack_needed: "None" - } - - if get_db_version >= '12.1' - @methods << { type: :sql_translation, - description: "Generates a script for using SQL translation framework.\nThis allows to replace all parts of the SQL statement as long as the number and types of bind variables remain the same,", - option_pack_needed: "Enterprise Edition" - } - end - - @methods.each {|m| m.extend(SelectHashHelper) } render_partial end @@ -1976,6 +1947,81 @@ def run_sql_tuning_advisor render_partial end + def generate_sql_plan_baseline_from_sga + sql_id = prepare_param :sql_id + plan_hash_value = prepare_param :plan_hash_value + force_matching_signature = prepare_param :force_matching_signature + exact_matching_signature = prepare_param :exact_matching_signature + + result = " +-- Build SQL plan baseline for SQL-ID = '#{sql_id}', plan hash value = #{plan_hash_value} +-- Generated with Panorama at #{Time.now} + +SET SERVEROUTPUT ON; + +DECLARE + cur sys_refcursor; + hit_count PLS_INTEGER; + sql_handle VARCHAR2(30); + plan_name VARCHAR2(30); +BEGIN + hit_count := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE ( + sql_id => '#{sql_id}', + plan_hash_value => #{plan_hash_value}, + fixed => 'YES', + enabled => 'YES' + ); + + -- Get access criteria for the new created baseline based on exact- or force-signature + SELECT SQL_Handle, Plan_Name INTO sql_handle, plan_name FROM DBA_SQL_Plan_Baselines + WHERE (Signature = #{force_matching_signature} OR Signature = #{exact_matching_signature}) + AND Created > SYSDATE-0.1; + + -- Set the description according to your choice (max. 500 chars) + hit_count := DBMS_SPM.ALTER_SQL_PLAN_BASELINE(SQL_Handle => sql_handle, Plan_Name => plan_name, Attribute_Name => 'description', Attribute_Value => 'Baseline generated by Panorama ...'); + + -- You can check the existence of the baseline now by executing: + -- SELECT * FROM dba_sql_plan_baselines; + -- or by looking at SQL details page for your SQL with Panorama + + -- Next commands remove currently existing cursors of this SQL from SGA to ensure hard parse with SQL plan baseline at next execution +" + + if PanoramaConnection.rac? + result << " -- Because your system uses RAC you should execute the following block with DBMS_SHARED_POOL.PURGE once again connected on the appropriate RAC-instance\n" + instances = sql_select_all(["SELECT Inst_ID FROM gv$SQLArea WHERE SQL_ID=?", sql_id]) + result << " -- at generation time of this script the SQL is loaded in SGA at this RAC instances: #{instances.map{|i| i.inst_id }.join(', ')}\n" + end + + result << " + FOR cu IN (SELECT RAWTOHEX(Address) Address, Hash_Value FROM v$SQLArea WHERE SQL_ID='#{sql_id}') LOOP + DBMS_SHARED_POOL.PURGE (cu.address||', '||cu.hash_value, 'C'); + DBMS_OUTPUT.PUT_LINE('Existing cursor for SQL-ID=#{sql_id} removed from SGA'); + END LOOP; +END; +/ + +-- ######### to remove an existing SQL plan baseline execute the following: +-- Get the SQL-Handle of your baseline from Panorama's selections or by +-- SELECT * FROM dba_sql_plan_baselines WHERE SQL_Text LIKE '%%'; + +-- Drop all baselines of the SQL with the given SQL-Handle +-- DECLARE +-- v_dropped_plans number; +-- BEGIN +-- v_dropped_plans := DBMS_SPM.DROP_SQL_PLAN_BASELINE (sql_handle => 'SQL_b6b0d1c71cd1807b'); +-- DBMS_OUTPUT.PUT_LINE('dropped ' || v_dropped_plans || ' plans'); +-- END; +-- / + +" + + respond_to do |format| + format.html {render :html => render_code_mirror(result) } + end + + end + def create_profile_from_sql_tuning_advisor_task @task_name = prepare_param :task_name PanoramaConnection.sql_execute ["BEGIN DBMS_SQLTUNE.accept_sql_profile(task_name => ?, name => ?, task_owner => USER, replace => TRUE); END;", @task_name, @task_name] diff --git a/app/views/dba_sga/_influence_sql_plan.html.erb b/app/views/dba_sga/_influence_sql_plan.html.erb index 1e1b160d..b9236b81 100644 --- a/app/views/dba_sga/_influence_sql_plan.html.erb +++ b/app/views/dba_sga/_influence_sql_plan.html.erb @@ -1,69 +1,126 @@ <% @update_area = get_unique_area_id - show_action = proc do |rec| - case rec.type - when :sql_tuning_advisor - disabled = PanoramaConnection.management_pack_license != :diagnostics_and_tuning_pack - title = "Run Oracle's builtin SQL Tuning Advisor for this SQL to automatically find a better execution plan." - title = "SQL Tuning Advisor requires Enterprise Edition with Diagnostics and Tuning Pack." if PanoramaConnection.management_pack_license != :diagnostics_and_tuning_pack + @methods = [] - ajax_submit('SQL Tuning Advisor', { - :controller => :dba_sga, - :action => :show_sql_tuning_advisor, - :update_area => @update_area, - :sql_id => @sql_id, - min_snap_id: @min_snap_id, - max_snap_id: @max_snap_id, - dbid: @dbid - }, :disabled => disabled, :title=> title) + #### sql_tuning_advisor + disabled = PanoramaConnection.management_pack_license != :diagnostics_and_tuning_pack + title = "Run Oracle's builtin SQL Tuning Advisor for this SQL to automatically find a better execution plan." + title = "SQL Tuning Advisor requires Enterprise Edition with Diagnostics and Tuning Pack." if PanoramaConnection.management_pack_license != :diagnostics_and_tuning_pack + action = ajax_submit('SQL Tuning Advisor', { + :controller => :dba_sga, + :action => :show_sql_tuning_advisor, + :update_area => @update_area, + :sql_id => @sql_id, + min_snap_id: @min_snap_id, + max_snap_id: @max_snap_id, + dbid: @dbid + }, :disabled => disabled, :title=> title) + @methods << { type: :sql_tuning_advisor, + action: action.html_safe, + description: "Run Oracle's builtin SQL Tuning Advisor for this SQL to automatically find a better execution plan.\n\nADVISOR privilege is needed for the user to run the SQL Tuning Advisor.\nCREATE ANY SQL PROFILE privilege is needed to create a SQL profile from the result of the Tuning Advisor.", + option_pack_needed: "Enterprise Edition + Diagnostics and Tuning Pack" + } - when :plan_baseline then + #### plan_baseline + title = t(:dba_history_list_sql_detail_historic_create_baseline_hint, :default=>"Generate script to fix exactly this execution plan as SQL-baseline for this SQL.") + desc_add = "" + option_pack_needed = "" + if @min_snap_id && @max_snap_id # called from AWR view + desc_add << "\nBases on AWR data for choosen time period." + if get_db_version < '18' disabled = PanoramaConnection.edition == :standard || PanoramaConnection.management_pack_license != :diagnostics_and_tuning_pack - title = t(:dba_history_list_sql_detail_historic_create_baseline_hint, :default=>"Generate script to fix exactly this execution plan as SQL-baseline for this SQL.") - title = "Generation of SQL plan baseline from AWR requires Enterprise Edition with Diagnostics and Tuning Pack.\nYou may try to load SQLplan baseline from cursor cache instead (from current SGA)." if PanoramaConnection.edition == :standard || PanoramaConnection.management_pack_license != :diagnostics_and_tuning_pack - - ajax_submit('SQL plan baseline', { - :controller => :dba_history, - :action => :select_plan_hash_value_for_baseline, - :update_area => @update_area, - :sql_id => @sql_id, - :min_snap_id => @min_snap_id, - :max_snap_id => @max_snap_id, - :force_matching_signature => @force_matching_signature.to_s, - :exact_matching_signature => @exact_matching_signature.to_s - }, :disabled => disabled, :title=> title) - when :sql_profile then - ajax_submit('SQL Profile', { - :controller => :dba_sga, - :action => :generate_sql_profile, - :update_area => @update_area, - :sql_id => @sql_id, - }, :title=> "Generate script to create SQL profile for this SQL.") - when :sql_patch then - ajax_submit('SQL Patch', { - :controller => :dba_sga, - :action => :generate_sql_patch, - :update_area => @update_area, - :sql_id => @sql_id, - }, :title=> t(:dba_history_list_sql_detail_historic_create_sql_patch_hint, :default=>"Generate script to create SQL patch for this SQL.")) - when :sql_translation then - ajax_submit('SQL Translation', { - :controller => :dba_sga, - :action => :generate_sql_translation, - :update_area => @update_area, - :sql_id => @sql_id, - :user_name => @user_name, - }, :title=> t(:dba_history_list_sql_detail_historic_create_translation_hint, :default=>"Generate script to create profile for SQL-translation-framework for this SQL.")) - else "Unsupported type #{rec.type}" + desc_add << "\n\nGeneration of SQL plan baseline from AWR requires Enterprise Edition with Diagnostics and Tuning Pack.\nYou may try to load SQL plan baseline from cursor cache instead (from current SGA)." if disabled + option_pack_needed = "Enterprise Edition + Diagnostics and Tuning Pack" + else + disabled = PanoramaConnection.edition == :standard || PanoramaConnection.management_pack_license != :diagnostics_pack + desc_add << "\n\nGeneration of SQL plan baseline from AWR requires Enterprise Edition with Diagnostics Pack.\nYou may try to load SQLplan baseline from cursor cache instead (from current SGA)." if disabled + option_pack_needed = "Enterprise Edition + Diagnostics Pack" end + action = ajax_submit('SQL plan baseline', { + :controller => :dba_history, + :action => :select_plan_hash_value_for_baseline, + :update_area => @update_area, + :sql_id => @sql_id, + :min_snap_id => @min_snap_id, + :max_snap_id => @max_snap_id, + :force_matching_signature => @force_matching_signature.to_s, + :exact_matching_signature => @exact_matching_signature.to_s + }, :disabled => disabled, :title=> title) + else # called from SGA view + desc_add << "\nBases on current SGA data." + disabled = @plan_hash_value.nil? + desc_add << "\n\nGeneration of SQL plan baseline from SGA requires a unique plan hash value.\nPlease choose a SQL child cursor view with a unique plan hash value." if disabled + option_pack_needed = "none" + + action = ajax_submit('SQL plan baseline', { + :controller => :dba_sga, + :action => :generate_sql_plan_baseline_from_sga, + :update_area => @update_area, + :sql_id => @sql_id, + plan_hash_value: @plan_hash_value, + :force_matching_signature => @force_matching_signature.to_s, + :exact_matching_signature => @exact_matching_signature.to_s + }, :disabled => disabled, :title=> title) + end + @methods << { type: :plan_baseline, + action: action.html_safe, + description: "Generate script to fix exactly one execution plan as SQL-baseline for this SQL.#{desc_add}", + option_pack_needed: option_pack_needed + } + + #### sql_profile + action = ajax_submit('SQL Profile', { + :controller => :dba_sga, + :action => :generate_sql_profile, + :update_area => @update_area, + :sql_id => @sql_id, + }, :title=> "Generate template script to create a SQL profile for this SQL.") + + @methods << { type: :sql_profile, + action: action.html_safe, + description: "Generates commands for manual creation of a SQL profile.\nThis allows to inject your own defined optimizer hints to the SQL.", + option_pack_needed: "Enterprise Edition + Tuning Pack" + } + + #### sql_patch + action = ajax_submit('SQL Patch', { + :controller => :dba_sga, + :action => :generate_sql_patch, + :update_area => @update_area, + :sql_id => @sql_id, + }, :title=> t(:dba_history_list_sql_detail_historic_create_sql_patch_hint, :default=>"Generate template script to create SQL patch for this SQL.")) + + @methods << { type: :sql_patch, + action: action.html_safe, + description: "Generates commands for creation of a SQL patch.\nThis allows to inject your own defined optimizer hints to the SQL.\nSimilar to SQL profile, but without the need for licensed Tuning Pack.", + option_pack_needed: "None" + } + + if get_db_version >= '12.1' + #### sql_translation + action = ajax_submit('SQL Translation', { + :controller => :dba_sga, + :action => :generate_sql_translation, + :update_area => @update_area, + :sql_id => @sql_id, + :user_name => @user_name, + }, :title=> t(:dba_history_list_sql_detail_historic_create_translation_hint, :default=>"Generate template script to create profile for SQL-translation-framework for this SQL.")) + + @methods << { type: :sql_translation, + action: action.html_safe, + description: "Generates a script for using SQL translation framework.\nThis allows to replace all parts of the SQL statement as long as the number and types of bind variables remain the same,", + option_pack_needed: "Enterprise Edition" + } end + @methods.each {|m| m.extend(SelectHashHelper) } + column_options = [ - { caption: "Action", data: show_action, title: "Action to generate the script snippet to execute"}, - { caption: "Description", data: proc{|rec| rec.description }, title: "Description of influencing activity"}, - { caption: "Option pack needed", data: proc{|rec| rec.option_pack_needed }, title: "Needed licensing of option pack to use this function"}, + { caption: "Action", data: proc{|rec| rec[:action]}, title: "Action to generate the script snippet to execute"}, + { caption: "Description", data: proc{|rec| rec.description}, title: "Description of influencing activity"}, + { caption: "Option pack needed", data: proc{|rec| rec.option_pack_needed }, title: "Needed licensing of option pack to use this function"}, ] %> <%= gen_slickgrid(@methods, diff --git a/app/views/dba_sga/_list_sql_sga_stat_footer.html.erb b/app/views/dba_sga/_list_sql_sga_stat_footer.html.erb index c2d2ebd6..f88fe377 100644 --- a/app/views/dba_sga/_list_sql_sga_stat_footer.html.erb +++ b/app/views/dba_sga/_list_sql_sga_stat_footer.html.erb @@ -193,13 +193,14 @@
<%= ajax_submit('SQL plan mgmt.', { - controller: :dba_sga, - action: :influence_sql_plan, - update_area: @update_area, - sql_id: @sql_id, - user_name: @sql.parsing_schema_name, - force_signature: @sql.force_signature.to_s, - exact_signature: @sql.exact_signature.to_s, + controller: :dba_sga, + action: :influence_sql_plan, + update_area: @update_area, + sql_id: @sql_id, + user_name: @sql.parsing_schema_name, + force_matching_signature: @sql.force_signature.to_s, + exact_matching_signature: @sql.exact_signature.to_s, + plan_hash_value: (@sql[:plan_hash_value_count] && @sql[:plan_hash_value_count] == 1 ? @sql.plan_hash_value : nil), }, title: "Show methods to influence the execution plan without changing the SQL syntax of this SQL") %>
diff --git a/config/locales/de.yml b/config/locales/de.yml index abb520df..f54ddfeb 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -250,9 +250,9 @@ dba_history_list_sql_detail_historic_create_baseline_hint: |- Generiere ein Script, um diesen konkreten Ausführungsplan als SQL-Baseline festzuschreiben. dba_history_list_sql_detail_historic_create_sql_patch_hint: |- - Generiere ein Script, um für dieses SQL einen SQL-Patch zu erstellen. + Generiere ein Template-Script, um für dieses SQL einen SQL-Patch zu erstellen. dba_history_list_sql_detail_historic_create_translation_hint: |- - Generiere ein Script, um für dieses SQL ein Profil für das SQL-Translation-Framework zu erstellen. + Generiere ein Template-Script, um für dieses SQL ein Profil für das SQL-Translation-Framework zu erstellen. dba_history_list_sql_detail_historic_last_plan_hash_hint: Hash-Value des letzten Explain-Plans dba_history_list_sql_detail_historic_module_link_hint: Detaillierung des Modul-Namens dba_history_list_sql_detail_historic_module_action_hint: Module und Action der Session, von der Statement zuletzt geparst wurde