Skip to content

Commit 7c276fc

Browse files
committed
Merge remote-tracking branch 'refs/remotes/Microsoft/master'
2 parents 6ebfcb7 + a975756 commit 7c276fc

36 files changed

+1694
-178
lines changed

samples/databases/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ The new sample database for SQL Server 2016 and Azure SQL Database. It illustrat
99
__[contoso-data-warehouse](contoso-data-warehouse/)__
1010

1111
Sample data warehouse that illustrates loading data into Azure SQL Data Warehouse.
12+
13+
__[AdventureWorks2014](https://github.com/Microsoft/sql-server-samples/releases/tag/adventureworks2014)__
14+
15+
Sample databases and Analysis Services models for use with SQL Server 2014 and later.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp1.0</TargetFramework>
5+
<PreserveCompilationContext>true</PreserveCompilationContext>
6+
<AssemblyName>force-last-good-plan</AssemblyName>
7+
<OutputType>Exe</OutputType>
8+
<PackageId>force-last-good-plan</PackageId>
9+
<RuntimeFrameworkVersion>1.0.4</RuntimeFrameworkVersion>
10+
<PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback>
11+
</PropertyGroup>
12+
13+
<ItemGroup>
14+
<None Update="wwwroot\**\*">
15+
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
16+
</None>
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.0.3" />
21+
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="1.0.3" />
22+
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.0.2" />
23+
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.0.3" />
24+
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.0.2" />
25+
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.0.2" />
26+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.0.2" />
27+
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.0.2" />
28+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.0.2" />
29+
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.0.2" />
30+
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.0.2" />
31+
<PackageReference Include="System.Data.SqlClient" Version="4.3.0" />
32+
<PackageReference Include="Belgrade.Sql.Client" Version="0.7.0" />
33+
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
34+
</ItemGroup>
35+
36+
</Project>

samples/features/automatic-tuning/force-last-good-plan/sql-scripts/demo-full.sql

Lines changed: 72 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,74 @@
11
/********************************************************
22
* SETUP - clear everything
33
********************************************************/
4-
EXEC [dbo].[initialize]
5-
4+
ALTER DATABASE current SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = OFF);
5+
EXEC dbo.initialize;
66

77
/********************************************************
88
* PART I
9-
* Plan regression identification.
9+
* Plan regression identification & manual tuning
1010
********************************************************/
1111

12-
-- 1. Start workload - execute procedure 30-300 times:
13-
begin
14-
declare @packagetypeid int = 7;
15-
exec dbo.report @packagetypeid
16-
end
17-
go 300
18-
-- Queries should be fast
19-
-- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Hash Aggregate)
12+
-- Execute the query and include "Actual execution plan" in SSMS and show the plan - it should have Hash Match (Aggregate) operator with Columnstore Index Scan
13+
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
14+
from Sales.OrderLines
15+
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
16+
GO 60
17+
-- 1. Execute this query 45-300 times to setup the baseline.
18+
-- If you have QUERY_STORE CAPTURE_POLICY=AUTO increase number in GO <number> to at least 60
2019

2120

22-
-- 2. Execute procedure that causes plan regression
23-
-- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Stream Aggregate)
24-
exec dbo.regression
21+
-- 2. Execute the procedure that causes plan regression
22+
-- Optionally, include "Actual execution plan" in SSMS and show the plan - it should have Stream Aggregate, Index Seek & Nested Loops
23+
EXEC dbo.regression;
2524

2625

27-
-- 3. Start workload again - verify that is slower.
28-
begin
29-
declare @packagetypeid int = 7;
30-
exec dbo.report @packagetypeid
31-
end
26+
-- 3. Start the workload again - verify that is slower.
27+
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
28+
from Sales.OrderLines
29+
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
3230
go 20
33-
-- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Stream Aggregate)
31+
-- Optionally, include "Actual execution plan" in SSMS and show the plan - it should have Stream Aggregate with Non-clustered index seek.
3432

35-
-- 4. Find recommendation recommended by database:
36-
SELECT planForceDetails.query_id, reason, score,
37-
JSON_VALUE(details, '$.implementationDetails.script') [correction script],
38-
planForceDetails.[new plan_id], planForceDetails.[recommended plan_id]
39-
FROM sys.dm_db_tuning_recommendations
40-
CROSS APPLY OPENJSON (Details, '$.planForceDetails')
41-
WITH ( [query_id] int '$.queryId',
42-
[new plan_id] int '$.regressedPlanId',
43-
[recommended plan_id] int '$.recommendedPlanId'
44-
) as planForceDetails;
33+
-- 4. Find a recommendation that can fix this issue:
34+
SELECT reason, score,
35+
script = JSON_VALUE(details, '$.implementationDetails.script')
36+
FROM sys.dm_db_tuning_recommendations;
4537

38+
-- 4.1. Optionally get more detailed information about the regression and recommendation.
39+
SELECT reason, score,
40+
script = JSON_VALUE(details, '$.implementationDetails.script'),
41+
planForceDetails.[query_id],
42+
planForceDetails.[new plan_id],
43+
planForceDetails.[recommended plan_id],
44+
estimated_gain = (regressedPlanExecutionCount+recommendedPlanExecutionCount)*(regressedPlanCpuTimeAverage-recommendedPlanCpuTimeAverage)/1000000,
45+
error_prone = IIF(regressedPlanErrorCount>recommendedPlanErrorCount, 'YES','NO')
46+
FROM sys.dm_db_tuning_recommendations
47+
CROSS APPLY OPENJSON (Details, '$.planForceDetails')
48+
WITH ( [query_id] int '$.queryId',
49+
[new plan_id] int '$.regressedPlanId',
50+
[recommended plan_id] int '$.recommendedPlanId',
51+
regressedPlanErrorCount int,
52+
recommendedPlanErrorCount int,
53+
regressedPlanExecutionCount int,
54+
regressedPlanCpuTimeAverage float,
55+
recommendedPlanExecutionCount int,
56+
recommendedPlanCpuTimeAverage float ) as planForceDetails;
57+
-- IMPORTANT NOTE: check is estimated_gain > 10.
58+
-- If estimated_gain < 10 THEN FLGP=ON will not automatically force the plan!!!
59+
-- In that case increase the number of executions in initial workload.
60+
-- Make sure that SQL Engine uses columnstore in original plan and nonclustered index in regressed plan.
4661

4762
-- Note: User can apply script and force the recommended plan to correct the error.
4863
<<Insert T-SQL from the script column here and execute the script>>
4964
-- e.g.: exec sp_query_store_force_plan @query_id = 3, @plan_id = 1
5065

51-
-- 5. Start workload again - verify that is faster.
52-
begin
53-
declare @packagetypeid int = 7;
54-
exec dbo.report @packagetypeid
55-
end
56-
go 20
57-
-- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Hash Aggregate again)
66+
-- 5. Execute the query again - verify that it is faster.
67+
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
68+
from Sales.OrderLines
69+
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
70+
GO 20
71+
-- Optionally, include "Actual execution plan" in SSMS and show the plan - it should have Hash Aggregate & Columnstore again
5872

5973

6074
-- In part II will be shown better approach - automatic tuning.
@@ -74,29 +88,26 @@ ALTER DATABASE current
7488
SET AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = ON);
7589

7690
-- Verify that actual state on FLGP is ON:
77-
SELECT name, desired_state_desc, actual_state_desc, reason_desc
78-
FROM sys.database_automatic_tuning_options;
79-
91+
SELECT name, actual_state_desc, status = IIF(desired_state_desc <> actual_state_desc, reason_desc, 'Status:OK')
92+
FROM sys.database_automatic_tuning_options
93+
WHERE name = 'FORCE_LAST_GOOD_PLAN';
8094

8195
-- 1. Start workload - execute procedure 30-300 times like in the phase I
82-
begin
83-
declare @packagetypeid int = 7;
84-
exec dbo.report @packagetypeid
85-
end
86-
go 300
96+
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
97+
from Sales.OrderLines
98+
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
99+
GO 60
87100

88-
-- 2. Execute the procedure that causes plan regression
101+
-- 2. Execute the procedure that causes the plan regression
89102
exec dbo.regression;
90103

91-
-- 3. Start workload again - verify that it is slower.
92-
begin
93-
declare @packagetypeid int = 7;
94-
exec dbo.report @packagetypeid;
95-
end
96-
go 20
104+
-- 3. Start the workload again - verify that it is slower.
105+
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
106+
from Sales.OrderLines
107+
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
108+
go 30
97109

98-
-- 4. Find recommendation that returns query perf regression
99-
-- and check is it in Verifying state:
110+
-- 4. Find a recommendation and check is it in "Verifying" or "Success" state:
100111
SELECT reason, score,
101112
JSON_VALUE(state, '$.currentValue') state,
102113
JSON_VALUE(state, '$.reason') state_transition_reason,
@@ -110,11 +121,11 @@ FROM sys.dm_db_tuning_recommendations
110121
) as planForceDetails;
111122

112123

113-
-- 5. Wait until recommendation is applied and start workload again - verify that it is faster.
114-
begin
115-
declare @packagetypeid int = 7;
116-
exec dbo.report @packagetypeid
117-
end
118-
go 30
124+
-- 5. Recommendation is in "Verifying" state, but the last good plan is forced, so the query will be faster:
125+
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
126+
from Sales.OrderLines
127+
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
128+
129+
130+
-- Open Query Store/"Top Resource Consuming Queries" dialog in SSMS and show that the better plan is forced.
119131

120-
-- Open Query Store/"Top Resource Consuming Queries" dialog in SSMS and show that better plan is forced.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/***************************************************************************
2+
* Run this script on a empty database if you don't have WWI database and
3+
* you want to use new database instead of full WWI
4+
* If you are using SSMS, use Ctrl+Shift+M to populate parameters.
5+
***************************************************************************/
6+
ALTER DATABASE <database_name, sysname, flgp> MODIFY (EDITION = 'Premium', SERVICE_OBJECTIVE = '<azuredb_service_objective, varchar(6), P4>');
7+
SELECT DATABASEPROPERTYEX('<database_name, sysname, flgp>', 'ServiceObjective');
8+
-- Create minimal WWI schema required to run the sample:
9+
DROP TABLE IF EXISTS [Sales].[OrderLines];
10+
GO
11+
DROP SEQUENCE IF EXISTS [Sequences].[OrderLineID];
12+
GO
13+
DROP SCHEMA IF EXISTS [Sequences];
14+
GO
15+
DROP SCHEMA IF EXISTS [Sequences];
16+
GO
17+
18+
CREATE SCHEMA [Sequences];
19+
GO
20+
CREATE SEQUENCE [Sequences].[OrderLineID]
21+
AS [int]
22+
START WITH 231413
23+
INCREMENT BY 1
24+
MINVALUE -2147483648
25+
MAXVALUE 2147483647
26+
CACHE
27+
GO
28+
29+
CREATE TABLE [Sales].[OrderLines](
30+
[OrderLineID] [int] PRIMARY KEY,
31+
[OrderID] [int] NOT NULL,
32+
[StockItemID] [int] NOT NULL,
33+
[Description] [nvarchar](100) NOT NULL,
34+
[PackageTypeID] [int] NOT NULL,
35+
[Quantity] [int] NOT NULL,
36+
[UnitPrice] [decimal](18, 2) NULL,
37+
[TaxRate] [decimal](18, 3) NOT NULL,
38+
[PickedQuantity] [int] NOT NULL,
39+
[PickingCompletedWhen] [datetime2](7) NULL,
40+
[LastEditedBy] [int] NOT NULL,
41+
[LastEditedWhen] [datetime2](7) NOT NULL
42+
)
43+
GO
44+
ALTER TABLE [Sales].[OrderLines]
45+
ADD CONSTRAINT [DF_Sales_OrderLines_OrderLineID]
46+
DEFAULT (NEXT VALUE FOR [Sequences].[OrderLineID]) FOR [OrderLineID]
47+
GO
48+
ALTER TABLE [Sales].[OrderLines]
49+
ADD CONSTRAINT [DF_Sales_OrderLines_LastEditedWhen]
50+
DEFAULT (sysdatetime()) FOR [LastEditedWhen]
51+
GO
52+
DROP INDEX IF EXISTS [FK_Sales_OrderLines_PackageTypeID]
53+
ON [Sales].[OrderLines]
54+
55+
CREATE NONCLUSTERED INDEX [FK_Sales_OrderLines_PackageTypeID]
56+
ON [Sales].[OrderLines]([PackageTypeID] ASC)
57+
GO
58+
59+
60+
-- Export Sales.OrderLines from WWI database using bcp:
61+
-- bcp WideWorldImporters.Sales.OrderLines out OrderLines.dat -T -c -U <wwi_user_name, nvarchar(50), WWIUSERNAME> -P <wwi_password, nvarchar(50), WWIPASSWORD> -S <wwi server/instance, nvarchar(50), .//SQLEXPRESS>
62+
63+
-- Import data in new database using bcp:
64+
-- bcp <database_name, sysname, flgp>.Sales.OrderLines in OrderLines.dat -c -U <demo_user_name, nvarchar(50), DEMOUSERNAME> -P <demo_password, nvarchar(50), DEMOPASSWORD> -S <demo server/instance, nvarchar(50), .//SQLEXPRESS>

0 commit comments

Comments
 (0)