Created
May 20, 2025 10:07
-
-
Save BrentOzar/d9221f838775525fd02b642108d726c3 to your computer and use it in GitHub Desktop.
sp_auto_tuning_index_recommendation_verification_report.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
USE [master] | |
GO | |
/****** Object: StoredProcedure [sys].[sp_auto_tuning_index_recommendation_verification_report] Script Date: 5/20/2025 3:01:40 AM ******/ | |
SET ANSI_NULLS ON | |
GO | |
SET QUOTED_IDENTIFIER ON | |
GO | |
-- The original SP of runner has the following two parameters | |
-- @verification_action_start_time DATETIME = NULL, | |
-- @verification_action_duration TIME = NULL, | |
-- which reporting the verification timing, in new design is moved to the properties of | |
-- verification workflow, so update of those two parameters need to call verification's workflow update. | |
-- and the per query impact values will be represented as json string in the format: | |
-- '[{"hash": "0xD76DF8E7AEFC0102", "metric": 1, "before": 31, "after":30}, ...]'; | |
ALTER PROCEDURE [sys].[sp_auto_tuning_index_recommendation_verification_report] | |
( | |
@recommendation_id bigint, | |
@expected_ir_state int, | |
@execution_id uniqueidentifier, | |
@expected_wf_state int, | |
@reported_number_of_queries_with_improved_performance int=NULL, | |
@reported_number_of_queries_with_regressed_performance int=NULL, | |
@reported_cpu_utilization_change_absolute float=NULL, | |
@reported_cpu_utilization_change_relative float=NULL, | |
@reported_logical_reads_change_absolute float=NULL, | |
@reported_logical_reads_change_relative float=NULL, | |
@reported_logical_writes_change_absolute float=NULL, | |
@reported_logical_writes_change_relative float=NULL, | |
@reported_affected_queries_cpu_utilization_change_relative float=NULL, | |
@reported_affected_queries_logical_reads_change_relative float=NULL, | |
@reported_affected_queries_logical_writes_change_relative float=NULL, | |
@verification_progress_percent float = NULL, | |
@observed_query_level_impacts_json nvarchar(max)=NULL | |
) | |
AS | |
BEGIN | |
exec sys.sp_auto_tuning_validate_executable; | |
BEGIN TRAN tran_verification_report; | |
BEGIN TRY | |
IF @recommendation_id IS NULL | |
RAISERROR(15725, -1, 9, N'recommendation_id'); | |
IF @execution_id IS NULL | |
RAISERROR(15725, -1, 10, N'execution_id'); | |
IF @expected_wf_state IS NULL | |
RAISERROR(15725, -1, 11, N'expected_wf_state'); | |
IF @expected_ir_state IS NULL | |
RAISERROR(15725, -1, 12, N'expected_ir_state'); | |
DECLARE @return_status int; | |
DECLARE @sql_string nvarchar(max); | |
SET @sql_string = N' | |
DECLARE @query_impact_values TABLE( | |
[hash] binary(8), | |
[metric] smallint, | |
[before] float, | |
[after] float); | |
-- There will at most 10 impact queries, so the input string observed_query_level_impacts_json_in and temp table @query_impact_values | |
-- will not be huge. | |
IF @observed_query_level_impacts_json_in IS NOT NULL | |
BEGIN | |
INSERT INTO @query_impact_values([hash], [metric], [before], [after]) | |
SELECT CONVERT(binary(8), [hash], 1), [metric], [before], [after] | |
FROM OPENJSON(@observed_query_level_impacts_json_in) | |
WITH ( | |
[hash] nvarchar(18), | |
[metric] smallint, | |
[before] float, | |
[after] float | |
); | |
END | |
IF EXISTS(SELECT current_state FROM sys.ats_workflow_fsm WHERE execution_id=@execution_id_in AND current_state=@expected_wf_state_in) | |
BEGIN | |
IF EXISTS(SELECT state FROM sys.ats_recommendations WHERE id=@recommendation_id_in AND state=@expected_ir_state_in) | |
BEGIN | |
DECLARE @recommendation_impact_values TABLE ( | |
[dimension_id] smallint NOT NULL, | |
[impact_type_id] tinyint NOT NULL, | |
[unit_type_id] smallint, | |
[absolute_value] float, | |
[change_value_absolute] float, | |
[change_value_relative] float); | |
-- dimension_id dictionary: | |
-- SpaceChange : 0 | |
-- QueriesWithRegressedPerformance : 1 | |
-- CpuUtilization : 2 | |
-- LogicalReads : 3 | |
-- LogicalWrites : 4 | |
-- AffectedQueriesCpuUtilization : 5 | |
-- AffectedQueriesLogicalReads : 6 | |
-- AffectedQueriesLogicalWrites : 7 | |
-- VerificationProgress : 8 | |
-- QueriesWithImprovedPerformance : 9 | |
-- unit_type_id dictionary: | |
-- MegaBytes : 0 | |
-- CpuCores : 1 | |
-- ReadsPerSecond : 2 | |
-- WritesPerSecond : 3 | |
-- Percent : 4 | |
-- Count : 5 | |
-- impact_type_id dictionary: | |
-- Observed : 1 | |
-- Estimated : 0 | |
IF @reported_number_of_queries_with_regressed_performance_in IS NOT NULL | |
BEGIN | |
INSERT INTO @recommendation_impact_values ([dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (1, 5, CONVERT(float, @reported_number_of_queries_with_regressed_performance_in), NULL, NULL, 1) | |
END | |
IF @reported_cpu_utilization_change_absolute_in IS NOT NULL OR @reported_cpu_utilization_change_relative_in IS NOT NULL | |
BEGIN | |
INSERT INTO @recommendation_impact_values ([dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (2, 1, NULL, @reported_cpu_utilization_change_absolute_in, @reported_cpu_utilization_change_relative_in, 1) | |
END | |
IF @reported_logical_reads_change_absolute_in IS NOT NULL OR @reported_logical_reads_change_relative_in IS NOT NULL | |
BEGIN | |
INSERT INTO @recommendation_impact_values ([dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (3, 2, NULL, @reported_logical_reads_change_absolute_in, @reported_logical_reads_change_relative_in, 1) | |
END | |
IF @reported_logical_writes_change_absolute_in IS NOT NULL OR @reported_logical_writes_change_relative_in IS NOT NULL | |
BEGIN | |
INSERT INTO @recommendation_impact_values ([dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (4, 3, NULL, @reported_logical_writes_change_absolute_in, @reported_logical_writes_change_relative_in, 1) | |
END | |
IF @reported_cpu_utilization_change_absolute_in IS NOT NULL AND @reported_affected_queries_cpu_utilization_change_relative_in IS NOT NULL | |
BEGIN | |
INSERT INTO @recommendation_impact_values ([dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (5, 1, NULL, @reported_cpu_utilization_change_absolute_in, @reported_affected_queries_cpu_utilization_change_relative_in, 1) | |
END | |
IF @reported_logical_reads_change_absolute_in IS NOT NULL AND @reported_affected_queries_logical_reads_change_relative_in IS NOT NULL | |
BEGIN | |
INSERT INTO @recommendation_impact_values ([dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (6, 2, NULL, @reported_logical_reads_change_absolute_in, @reported_affected_queries_logical_reads_change_relative_in, 1) | |
END | |
IF @reported_logical_writes_change_absolute_in IS NOT NULL AND @reported_affected_queries_logical_writes_change_relative_in IS NOT NULL | |
BEGIN | |
INSERT INTO @recommendation_impact_values ([dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (7, 3, NULL, @reported_logical_writes_change_absolute_in, @reported_affected_queries_logical_writes_change_relative_in, 1) | |
END | |
IF @verification_progress_percent_in IS NOT NULL | |
BEGIN | |
INSERT INTO @recommendation_impact_values ([dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (8, 4, @verification_progress_percent_in, NULL, NULL, 1) | |
END | |
IF @reported_number_of_queries_with_improved_performance_in IS NOT NULL | |
BEGIN | |
INSERT INTO @recommendation_impact_values ([dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (9, 5, CONVERT(float, @reported_number_of_queries_with_improved_performance_in), NULL, NULL, 1) | |
END | |
-- insert/update the per recommendation impact values | |
MERGE sys.ats_recommended_impact_values AS [target] | |
USING @recommendation_impact_values AS [source] | |
ON ([target].[recommendation_id] = @recommendation_id_in | |
AND [target].[dimension_id] = [source].[dimension_id] | |
AND [target].[impact_type_id] = [source].[impact_type_id]) | |
WHEN MATCHED THEN | |
UPDATE SET | |
[unit_type_id] = [source].[unit_type_id], | |
[absolute_value] = [source].[absolute_value], | |
[change_value_absolute] = [source].[change_value_absolute], | |
[change_value_relative] = [source].[change_value_relative] | |
WHEN NOT MATCHED THEN | |
INSERT ([recommendation_id], [dimension_id], [unit_type_id], [absolute_value], [change_value_absolute], [change_value_relative], [impact_type_id]) | |
VALUES (@recommendation_id_in, [source].[dimension_id], [source].[unit_type_id], [source].[absolute_value], [source].[change_value_absolute], [source].[change_value_relative], [source].[impact_type_id]); | |
IF EXISTS(SELECT * FROM @query_impact_values) | |
BEGIN | |
-- insert/update the per query impact values | |
MERGE sys.ats_index_recommendation_impact_queries AS [target] | |
USING @query_impact_values AS [source] | |
ON ([target].[recommendation_id] = @recommendation_id_in | |
AND [target].[query_hash] = [source].[hash] | |
AND [target].[metric] = [source].[metric]) | |
WHEN MATCHED THEN | |
UPDATE SET | |
[avg_metric_before_action] = [source].[before], | |
[avg_metric_after_action] = [source].[after] | |
WHEN NOT MATCHED THEN | |
INSERT ([recommendation_id], [query_hash], [metric], [avg_metric_before_action], [avg_metric_after_action]) | |
VALUES (@recommendation_id_in, [source].[hash], [source].[metric], [source].[before], [source].[after]); | |
END | |
UPDATE sys.ats_index_recommendations | |
SET | |
reported_number_of_queries_with_improved_performance_cached = coalesce(@reported_number_of_queries_with_improved_performance_in, reported_number_of_queries_with_improved_performance_cached), | |
reported_number_of_queries_with_regressed_performance_cached = coalesce(@reported_number_of_queries_with_regressed_performance_in, reported_number_of_queries_with_regressed_performance_cached), | |
reported_cpu_utilization_change_absolute_cached = coalesce(@reported_cpu_utilization_change_absolute_in, reported_cpu_utilization_change_absolute_cached), | |
reported_cpu_utilization_change_relative_cached = coalesce(@reported_cpu_utilization_change_relative_in, reported_cpu_utilization_change_relative_cached), | |
reported_logical_reads_change_absolute_cached = coalesce(@reported_logical_reads_change_absolute_in, reported_logical_reads_change_absolute_cached), | |
reported_logical_reads_change_relative_cached = coalesce(@reported_logical_reads_change_relative_in, reported_logical_reads_change_relative_cached), | |
reported_logical_writes_change_absolute_cached = coalesce(@reported_logical_writes_change_absolute_in, reported_logical_writes_change_absolute_cached), | |
reported_logical_writes_change_relative_cached = coalesce(@reported_logical_writes_change_relative_in, reported_logical_writes_change_relative_cached) | |
WHERE id = @recommendation_id_in; | |
END | |
ELSE | |
BEGIN | |
DECLARE @message2 nvarchar(4000) = ''Recommendation ID:''+ISNULL(CONVERT(nvarchar(128), @recommendation_id_in), ''null'')+'' does not exist or state: ''+ISNULL(CONVERT(nvarchar(128), @expected_ir_state_in), ''null'') + '' does not exists!''; | |
RAISERROR(15726, -1, 4, @message2); | |
END | |
END | |
ELSE | |
BEGIN | |
DECLARE @message1 nvarchar(4000) = ''Workflow ID:''+ISNULL(CONVERT(nvarchar(128), @execution_id_in), ''null'')+'' does not exist or state: ''+ISNULL(CONVERT(nvarchar(128), @expected_wf_state_in), ''null'') + '' does not exists!''; | |
RAISERROR(15726, -1, 5, @message1); | |
END | |
'; | |
DECLARE @params_def nvarchar(4000); | |
SET @params_def = N' | |
@recommendation_id_in bigint, | |
@expected_ir_state_in int, | |
@execution_id_in uniqueidentifier, | |
@expected_wf_state_in int, | |
@reported_number_of_queries_with_improved_performance_in int, | |
@reported_number_of_queries_with_regressed_performance_in int, | |
@reported_cpu_utilization_change_absolute_in float, | |
@reported_cpu_utilization_change_relative_in float, | |
@reported_logical_reads_change_absolute_in float, | |
@reported_logical_reads_change_relative_in float, | |
@reported_logical_writes_change_absolute_in float, | |
@reported_logical_writes_change_relative_in float, | |
@reported_affected_queries_cpu_utilization_change_relative_in float, | |
@reported_affected_queries_logical_reads_change_relative_in float, | |
@reported_affected_queries_logical_writes_change_relative_in float, | |
@verification_progress_percent_in float = NULL, | |
@observed_query_level_impacts_json_in nvarchar(max) | |
'; | |
EXEC @return_status = sp_executesql @sql_string, | |
@params_def, | |
@recommendation_id_in=@recommendation_id, | |
@expected_ir_state_in=@expected_ir_state, | |
@execution_id_in=@execution_id, | |
@expected_wf_state_in=@expected_wf_state, | |
@reported_number_of_queries_with_improved_performance_in=@reported_number_of_queries_with_improved_performance, | |
@reported_number_of_queries_with_regressed_performance_in=@reported_number_of_queries_with_regressed_performance, | |
@reported_cpu_utilization_change_absolute_in=@reported_cpu_utilization_change_absolute, | |
@reported_cpu_utilization_change_relative_in=@reported_cpu_utilization_change_relative, | |
@reported_logical_reads_change_absolute_in=@reported_logical_reads_change_absolute, | |
@reported_logical_reads_change_relative_in=@reported_logical_reads_change_relative, | |
@reported_logical_writes_change_absolute_in=@reported_logical_writes_change_absolute, | |
@reported_logical_writes_change_relative_in=@reported_logical_writes_change_relative, | |
@reported_affected_queries_cpu_utilization_change_relative_in=@reported_affected_queries_cpu_utilization_change_relative, | |
@reported_affected_queries_logical_reads_change_relative_in=@reported_affected_queries_logical_reads_change_relative, | |
@reported_affected_queries_logical_writes_change_relative_in=@reported_affected_queries_logical_writes_change_relative, | |
@verification_progress_percent_in=@verification_progress_percent, | |
@observed_query_level_impacts_json_in=@observed_query_level_impacts_json; | |
IF @return_status != 0 | |
BEGIN | |
ROLLBACK TRAN tran_verification_report; | |
RAISERROR(15723, -1, 8, @return_status); | |
END | |
ELSE | |
COMMIT TRAN tran_verification_report; | |
RETURN 0 | |
END TRY | |
BEGIN CATCH | |
ROLLBACK TRAN tran_verification_report; | |
THROW; | |
END CATCH | |
END |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment