Merge remote-tracking branch 'refs/remotes/origin/master' into jodebrui

This commit is contained in:
Jos de Bruijn
2016-11-10 13:50:39 -08:00
51 changed files with 4039 additions and 12 deletions
+10
View File
@@ -3,6 +3,16 @@ This GitHub repository contains code samples that demonstrate how to use Microso
Note that certain features like In-Memory OLTP are edition specific for SQL Server and would be possible to implement if the edition which supports that feature is being used to run the sample.
## Releases in this repository
Releases allow you to conveniently download sample databases or applications without the need to build them from source code. This SQL Server samples repository has the following notable releases:
- [Wide World Importers sample database v1.0](https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0) is the main sample for SQL Server 2016 and Azure SQL Database. It contains both an OLTP and an OLAP database.
- [In-Memory OLTP Performance Demo v1.0](https://github.com/Microsoft/sql-server-samples/releases/tag/in-memory-oltp-demo-v1.0) illustrates the performance benefits of the In-Memory OLTP technology built into SQL Server and Azure SQL Database.
- [IoT Smart Grid sample v1.0](https://github.com/Microsoft/sql-server-samples/releases/tag/iot-smart-grid-v1.0) illustrates how SQL Server can be leveraged to ingest data from IoT devices and sensors, and how you can run analytics on that data.
To see the complete list of resources in this repository, navigate to [Releases](https://github.com/Microsoft/sql-server-samples/releases)
## Working in GitHub
To work in GitHub, go to https://github.com/microsoft/sql-server-samples and fork the repository. Work in your own fork and when you are ready to submit to make a change or publish your sample for the first time, submit a pull request into the master branch of sql-server-samples. One of the approvers will review your request and accept or reject the pull request.
+8
View File
@@ -4,10 +4,18 @@ __[applications] (applications/)__
End-to-end sample applications that illustrate the use of SQL Server for specific application scenarios.
__[connect] (connect/)__
Samples showing how to connect to SQL databases using various programming languages, including Python, C#, Java, Ruby, and Node.js.
__[databases] (databases/)__
Sample databases for SQL Server, Azure SQL Database, and Azure SQL Data Warehouse.
__[demos] (demos/)__
Demos of various SQL features and capabilities that were presented at conferences, in Webcasts, etc...
__[features] (features/)__
Samples illustrating specific SQL Server and Azure SQL Database features, including In-Memory OLTP, Master Data Services (MDS), and R Services.
@@ -2072,7 +2072,7 @@ BEGIN
PRINT 'Targeting ' + CAST(@NumberOfSalesPerDay AS varchar(20)) + ' sales per day.';
IF @NumberOfSalesPerDay > 50000
BEGIN
PRINT 'WARNING: Limiting sales to 40000 per day';
PRINT 'WARNING: Limiting sales to 50000 per day';
SET @NumberOfSalesPerDay = 50000;
END;
@@ -0,0 +1,62 @@
-- Free the procedure cache using dbcc freeproccache
DBCC FREEPROCCACHE
GO
-- Execute one of the queries below and just after you do, launch Activity Monitor inside SSMS
-- Expand the "Active Expensive Queries" tab
-- Right click on this query and click on "Show Live Execution Plan"
-- Query 1
USE AdventureWorks2014
GO
SELECT e.[BusinessEntityID],
p.[Title],
p.[FirstName],
p.[MiddleName],
p.[LastName],
p.[Suffix],
e.[JobTitle],
pp.[PhoneNumber],
pnt.[Name] AS [PhoneNumberType],
ea.[EmailAddress],
p.[EmailPromotion],
a.[AddressLine1],
a.[AddressLine2],
a.[City],
sp.[Name] AS [StateProvinceName],
a.[PostalCode],
cr.[Name] AS [CountryRegionName],
p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] AS e
INNER JOIN [Person].[Person] AS p
ON RTRIM(LTRIM(p.[BusinessEntityID])) = RTRIM(LTRIM(e.[BusinessEntityID]))
INNER JOIN [Person].[BusinessEntityAddress] AS bea
ON RTRIM(LTRIM(bea.[BusinessEntityID])) = RTRIM(LTRIM(e.[BusinessEntityID]))
INNER JOIN [Person].[Address] AS a
ON RTRIM(LTRIM(a.[AddressID])) = RTRIM(LTRIM(bea.[AddressID]))
INNER JOIN [Person].[StateProvince] AS sp
ON RTRIM(LTRIM(sp.[StateProvinceID])) = RTRIM(LTRIM(a.[StateProvinceID]))
INNER JOIN [Person].[CountryRegion] AS cr
ON RTRIM(LTRIM(cr.[CountryRegionCode])) = RTRIM(LTRIM(sp.[CountryRegionCode]))
LEFT OUTER JOIN [Person].[PersonPhone] AS pp
ON RTRIM(LTRIM(pp.BusinessEntityID)) = RTRIM(LTRIM(p.[BusinessEntityID]))
LEFT OUTER JOIN [Person].[PhoneNumberType] AS pnt
ON RTRIM(LTRIM(pp.[PhoneNumberTypeID])) = RTRIM(LTRIM(pnt.[PhoneNumberTypeID]))
LEFT OUTER JOIN [Person].[EmailAddress] AS ea
ON RTRIM(LTRIM(p.[BusinessEntityID])) = RTRIM(LTRIM(ea.[BusinessEntityID]))
OPTION (QUERYTRACEON 9481)
GO
-- Query 2
USE AdventureWorks2014;
GO
DBCC DROPCLEANBUFFERS;
GO
;WITH Prices AS (
SELECT dbo.ufnGetProductDealerPrice(d.ProductID, h.OrderDate) AS Price,
ROW_NUMBER() over(ORDER BY p.MiddleNAme) rn, p.PersonType, pr.Color
FROM Sales.SalesOrderDetail AS d
INNER JOIN Sales.SalesOrderHeader AS h ON h.SalesOrderID = d.SalesOrderID
INNER JOIN Person.Person AS p ON h.CustomerID = p.BusinessEntityID
INNER JOIN Production.Product AS pr ON d.ProductID = pr.ProductID
) SELECT * FROM Prices;
GO
@@ -0,0 +1,61 @@
-- Free the procedure cache using dbcc freeproccache
DBCC FREEPROCCACHE
GO
-- Click on Include Live Query Statistics SSMS button (next to Include Actual Execution Plan)
-- Execute one of the queries below
-- Query 1
USE AdventureWorks2014
GO
SELECT e.[BusinessEntityID],
p.[Title],
p.[FirstName],
p.[MiddleName],
p.[LastName],
p.[Suffix],
e.[JobTitle],
pp.[PhoneNumber],
pnt.[Name] AS [PhoneNumberType],
ea.[EmailAddress],
p.[EmailPromotion],
a.[AddressLine1],
a.[AddressLine2],
a.[City],
sp.[Name] AS [StateProvinceName],
a.[PostalCode],
cr.[Name] AS [CountryRegionName],
p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] AS e
INNER JOIN [Person].[Person] AS p
ON RTRIM(LTRIM(p.[BusinessEntityID])) = RTRIM(LTRIM(e.[BusinessEntityID]))
INNER JOIN [Person].[BusinessEntityAddress] AS bea
ON RTRIM(LTRIM(bea.[BusinessEntityID])) = RTRIM(LTRIM(e.[BusinessEntityID]))
INNER JOIN [Person].[Address] AS a
ON RTRIM(LTRIM(a.[AddressID])) = RTRIM(LTRIM(bea.[AddressID]))
INNER JOIN [Person].[StateProvince] AS sp
ON RTRIM(LTRIM(sp.[StateProvinceID])) = RTRIM(LTRIM(a.[StateProvinceID]))
INNER JOIN [Person].[CountryRegion] AS cr
ON RTRIM(LTRIM(cr.[CountryRegionCode])) = RTRIM(LTRIM(sp.[CountryRegionCode]))
LEFT OUTER JOIN [Person].[PersonPhone] AS pp
ON RTRIM(LTRIM(pp.BusinessEntityID)) = RTRIM(LTRIM(p.[BusinessEntityID]))
LEFT OUTER JOIN [Person].[PhoneNumberType] AS pnt
ON RTRIM(LTRIM(pp.[PhoneNumberTypeID])) = RTRIM(LTRIM(pnt.[PhoneNumberTypeID]))
LEFT OUTER JOIN [Person].[EmailAddress] AS ea
ON RTRIM(LTRIM(p.[BusinessEntityID])) = RTRIM(LTRIM(ea.[BusinessEntityID]))
OPTION (QUERYTRACEON 9481)
GO
-- Query 2
USE AdventureWorks2014;
GO
DBCC DROPCLEANBUFFERS;
GO
;WITH Prices AS (
SELECT dbo.ufnGetProductDealerPrice(d.ProductID, h.OrderDate) AS Price,
ROW_NUMBER() over(ORDER BY p.MiddleNAme) rn, p.PersonType, pr.Color
FROM Sales.SalesOrderDetail AS d
INNER JOIN Sales.SalesOrderHeader AS h ON h.SalesOrderID = d.SalesOrderID
INNER JOIN Person.Person AS p ON h.CustomerID = p.BusinessEntityID
INNER JOIN Production.Product AS pr ON d.ProductID = pr.ProductID
) SELECT * FROM Prices;
GO
+2
View File
@@ -0,0 +1,2 @@
Each file has instructions as comments on how to run the demo. Please mind the USE clauses.
If a specific DB is needed other than AdventureworksXXXX, then you will find the Setup script in the same folder.
@@ -0,0 +1,18 @@
The plan comparison tool is used inside Query Store UI to allow plan comparison.
###Prerequisites
Restore QueryStoreTest database from provided .bacpac (/Databases/Import Data-tier application).
###Query with plan regression
1. Run QueryStoreSimpleDemo.exe with option R
2. Open SSMS, and under QueryStoreTest database, expand Query Store.
3. Open the *Top Resource Consuming Queries* report.
4. For query id 1 there are two execution plans that SQL Server use alternately (switches between 2 plan almost randomly).
5. Select one of the plans in the right pane, and while holding the Shift key, select the other plan.
6. On the top ribbon in the same pane, click on *Compare the plans for the selected query in a seperate window* - this brings up Plan Comparison.
7. In the *Properties* window you are able to spot some differences in the SELECT node. Expand the *Parameter List* and observe how the *Parameter Compiled Value* is different on both plans.
This is known as Parameter Sniffing problem - plan gets generated based on parameter available at the compilation time.
When compilation happens frequently and randomly and data is skewed (not all parameter values are uniformly distributed).
Knowing the cause, you can chose to force the perceived better plan for most use cases.
This can fix performance quickly and is fully transparent to running apps.
@@ -0,0 +1,6 @@
Simply open SSMS, open a query execution plan file (.sqlplan) using File -> Open File, or drag a plan file to SSMS window.
Once the file opens, right-click anywhere inside the tab (not necessarily on top of an operator) and select “Compare Showplan” to get the other .sqlplan file to compare.
This works with any .sqlplan files you have, even from older versions of SQL Server.
Also, this is an offline compare, so theres no need to be connected to a SQL Server instance.
More information on the Plan Comparison Tool can beb found at https://blogs.msdn.microsoft.com/sql_server_team/tag/comparison-tool
@@ -0,0 +1,52 @@
-- Param Sniffing with Hash Spill
-- Setup
--USE AdventureWorks2014
USE AdventureWorks2016CTP3
GO
DROP TABLE CustomersState
GO
CREATE TABLE CustomersState (CustomerID int PRIMARY KEY, [Address] CHAR(200), [State] CHAR(2))
GO
INSERT INTO CustomersState (CustomerID, [Address])
SELECT CustomerID, 'Address' FROM Sales.Customer
GO
UPDATE CustomersState SET [State] = 'NY' WHERE CustomerID % 100 <> 1
UPDATE CustomersState SET [State] = 'WA' WHERE CustomerID % 100 = 1
GO
UPDATE STATISTICS CustomersState WITH FULLSCAN
GO
CREATE PROCEDURE CustomersByState @State CHAR(2) AS
BEGIN
DECLARE @CustomerID int
SELECT @CustomerID = e.CustomerID FROM Sales.Customer e
INNER JOIN CustomersState es ON e.CustomerID = es.CustomerID
WHERE es.[State] = @State
OPTION (MAXDOP 1)
END
GO
-- Get Actual Execution Plan
-- Execute the stored procedure first with parameter value WA which will select 1% of data.
DBCC FREEPROCCACHE
GO
EXEC CustomersByState 'WA'
GO
EXEC CustomersByState 'NY'
GO
/*
Observe the type of Spill = Recursion
Occurs when the build input does not fit into available memory,
resulting in the split of input into multiple partitions that are processed separately.
If any of these partitions still do not fit into available memory,
it is split into sub-partitions, which are also processed separately.
This splitting process continues until each partition fits into available memory
or until the maximum recursion level is reached.
In this case it stopped at level 1.
*/
@@ -0,0 +1,21 @@
-- Mem Grant Warning
-- Added MIN_GRANT_PERCENT for repro on SQL 2014 SP2 and 2016 only, because fix for this scenario is in those releases.
--Execute in 2014 for warning; coming soon for 2016
USE [memgrants]
GO
DBCC FREEPROCCACHE
GO
SELECT o.col3, o.col2, d.col2
FROM orders o
JOIN orders_detail d ON o.col2 = d.col1
WHERE o.col3 <= 8000
OPTION (LOOP JOIN, MAXDOP 1, MIN_GRANT_PERCENT = 20)
GO
/*
In SELECT node properties:
MaxQueryMemory for maximum query memory grant under RG MAX_MEMORY_PERCENT hint
MaxCompileMemory for maximum query optimizer memory in KB during compile under RG
*/
@@ -0,0 +1,71 @@
USE [master]
GO
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'memgrants')
CREATE DATABASE [memgrants]
GO
USE [memgrants]
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[orders]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[orders](
[col1] [int] NOT NULL,
[col2] [int] NULL,
[col3] [int] NULL,
PRIMARY KEY CLUSTERED
(
[col1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET NOCOUNT ON
GO
DECLARE @x int
SET @x = 0
WHILE (@x < 10000000)
BEGIN
INSERT INTO [dbo].[orders] VALUES (@x, @x, @x)
SET @x = @x + 1
END
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[orders_detail]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[orders_detail](
[col1] [int] NULL,
[col2] [int] NULL,
[col3] [char](5000) NOT NULL
) ON [PRIMARY]
END
GO
DECLARE @x int
DECLARE @y int
SET @x = 0
SET @y = 1
WHILE (@x < 10000)
BEGIN
INSERT INTO [dbo].[orders_detail] VALUES (@x, @y, 'x')
IF ((@y % 100) = 0)
BEGIN
SET @y = 1
SET @x = @x + 1
END
SET @y = @y + 1
END
GO
SET NOCOUNT OFF
GO
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[orders_detail]') AND name = N'od_cl_idx')
CREATE UNIQUE CLUSTERED INDEX [od_cl_idx] ON [dbo].[orders_detail]
(
[col1] ASC,
[col2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
@@ -0,0 +1,2 @@
Each file has instructions as comments on how to run the demo. Please mind the USE clauses.
If a specific DB is needed other than AdventureworksXXXX, then you will find the Setup script in the same folder.
@@ -0,0 +1,21 @@
-- Sort Spill
-- Get Actual Execution Plan
USE AdventureWorks2014
--USE AdventureWorks2016CTP3
GO
--Execute
DBCC FREEPROCCACHE
GO
SELECT *
FROM Sales.SalesOrderDetail SOD
INNER JOIN Production.Product P ON SOD.ProductID = P.ProductID
ORDER BY Style
OPTION (QUERYTRACEON 9481)
GO
/*
Observe the type of Spill = 1
Means one pass over the data was enough to complete the sort in the Worktable
*/
@@ -0,0 +1,68 @@
-- Param Sniffing with Hash Spill
-- Setup
--USE AdventureWorks2014
USE AdventureWorks2016CTP3
GO
DROP TABLE CustomersState
GO
CREATE TABLE CustomersState (CustomerID int PRIMARY KEY, [Address] CHAR(200), [State] CHAR(2))
GO
INSERT INTO CustomersState (CustomerID, [Address])
SELECT CustomerID, 'Address' FROM Sales.Customer
GO
UPDATE CustomersState SET [State] = 'NY' WHERE CustomerID % 100 <> 1
UPDATE CustomersState SET [State] = 'WA' WHERE CustomerID % 100 = 1
GO
UPDATE STATISTICS CustomersState WITH FULLSCAN
GO
CREATE PROCEDURE CustomersByState @State CHAR(2) AS
BEGIN
DECLARE @CustomerID int
SELECT @CustomerID = e.CustomerID FROM Sales.Customer e
INNER JOIN CustomersState es ON e.CustomerID = es.CustomerID
WHERE es.[State] = @State
OPTION (MAXDOP 1)
END
GO
-- Create xEvent session
DROP EVENT SESSION [HashSpills] ON SERVER
GO
CREATE EVENT SESSION [HashSpills] ON SERVER
ADD EVENT sqlserver.hash_spill_details(
ACTION(sqlserver.database_name,sqlserver.is_system,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_nt_username,sqlserver.sql_text)),
ADD EVENT sqlserver.hash_warning(
ACTION(sqlserver.database_name,sqlserver.is_system,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.session_nt_username,sqlserver.sql_text))
--ADD TARGET package0.ring_buffer(SET max_memory=(25600))
ADD TARGET package0.event_file(SET filename=N'C:\IP\Tiger\TR23\Demos\Demo 1.1 - Spills\HashSpills.xel',max_file_size=(50),max_rollover_files=(2))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO
--Execute the stored procedure first with parameter value WA which will select 1% of data.
DBCC FREEPROCCACHE
GO
ALTER EVENT SESSION [HashSpills] ON SERVER STATE = START
GO
EXEC CustomersByState 'WA'
GO
EXEC CustomersByState 'NY'
GO
ALTER EVENT SESSION [HashSpills] ON SERVER STATE = STOP
GO
/*
Observe the type of Spill = Recursion
Occurs when the build input does not fit into available memory,
resulting in the split of input into multiple partitions that are processed separately.
If any of these partitions still do not fit into available memory,
it is split into sub-partitions, which are also processed separately.
This splitting process continues until each partition fits into available memory
or until the maximum recursion level is reached.
In this case it stopped at level 1.
*/
@@ -0,0 +1,38 @@
-- Mem Grant xEvents
-- Added MIN_GRANT_PERCENT for repro on SQL 2014 SP2 and 2016 only, because fix for this scenario is in those releases.
-- Create xEvent session in 2016
-- Detect inaccurate or insufficient memory grant, when grant is >5MB as minimum
DROP EVENT SESSION [MemoryGrantXE] ON SERVER
GO
CREATE EVENT SESSION [MemoryGrantXE] ON SERVER
/*
ADD EVENT sqlserver.query_memory_grant_blocking(
ACTION(sqlserver.database_name,sqlserver.is_system,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_hash_signed,sqlserver.query_plan_hash,sqlserver.query_plan_hash_signed,sqlserver.session_nt_username,sqlserver.sql_text)),
ADD EVENT sqlserver.query_memory_grant_resource_semaphores(
ACTION(sqlserver.database_name,sqlserver.is_system,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_hash_signed,sqlserver.query_plan_hash,sqlserver.query_plan_hash_signed,sqlserver.session_nt_username,sqlserver.sql_text)),
ADD EVENT sqlserver.query_memory_grants(
ACTION(sqlserver.database_name,sqlserver.is_system,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_hash_signed,sqlserver.query_plan_hash,sqlserver.query_plan_hash_signed,sqlserver.session_nt_username,sqlserver.sql_text)),
*/
ADD EVENT sqlserver.query_memory_grant_usage(
ACTION(sqlserver.database_name,sqlserver.is_system,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_hash_signed,sqlserver.query_plan_hash,sqlserver.query_plan_hash_signed,sqlserver.session_nt_username,sqlserver.sql_text))
ADD TARGET package0.event_file(SET filename=N'C:\IP\Tiger\TR23\Demos\Demo 1.2 - Memory Grant XE\MemoryGrant.xel',max_file_size=(20))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO
-- Execute in 2016 for xEvent
USE [memgrants]
GO
DBCC FREEPROCCACHE
GO
ALTER EVENT SESSION [MemoryGrantXE] ON SERVER STATE = START
GO
SELECT o.col3, o.col2, d.col2
FROM orders o
JOIN orders_detail d ON o.col2 = d.col1
WHERE o.col3 <= 8000
OPTION (LOOP JOIN, MAXDOP 1, MIN_GRANT_PERCENT = 20)
GO
ALTER EVENT SESSION [MemoryGrantXE] ON SERVER STATE = STOP
GO
@@ -0,0 +1,71 @@
USE [master]
GO
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'memgrants')
CREATE DATABASE [memgrants]
GO
USE [memgrants]
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[orders]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[orders](
[col1] [int] NOT NULL,
[col2] [int] NULL,
[col3] [int] NULL,
PRIMARY KEY CLUSTERED
(
[col1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET NOCOUNT ON
GO
DECLARE @x int
SET @x = 0
WHILE (@x < 10000000)
BEGIN
INSERT INTO [dbo].[orders] VALUES (@x, @x, @x)
SET @x = @x + 1
END
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[orders_detail]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[orders_detail](
[col1] [int] NULL,
[col2] [int] NULL,
[col3] [char](5000) NOT NULL
) ON [PRIMARY]
END
GO
DECLARE @x int
DECLARE @y int
SET @x = 0
SET @y = 1
WHILE (@x < 10000)
BEGIN
INSERT INTO [dbo].[orders_detail] VALUES (@x, @y, 'x')
IF ((@y % 100) = 0)
BEGIN
SET @y = 1
SET @x = @x + 1
END
SET @y = @y + 1
END
GO
SET NOCOUNT OFF
GO
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[orders_detail]') AND name = N'od_cl_idx')
CREATE UNIQUE CLUSTERED INDEX [od_cl_idx] ON [dbo].[orders_detail]
(
[col1] ASC,
[col2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
@@ -0,0 +1,42 @@
-- Make sure Optimize for Adhoc Workloads is not active if demo'ing - that is why mt demo failed.
DROP EVENT SESSION [QueryProfileXE] ON SERVER
GO
CREATE EVENT SESSION [QueryProfileXE] ON SERVER
ADD EVENT sqlserver.query_thread_profile(
ACTION(sqlos.scheduler_id,sqlserver.database_id,sqlserver.is_system,sqlserver.plan_handle,sqlserver.query_hash_signed,sqlserver.query_plan_hash_signed,sqlserver.server_instance_name,sqlserver.session_id,sqlserver.session_nt_username,sqlserver.sql_text))
ADD TARGET package0.event_file(SET filename=N'C:\Demos\QueryProfileXE.xel',max_file_size=(50),max_rollover_files=(2))
--ADD TARGET package0.ring_buffer(SET max_memory=(25600))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO
-- Get Actual Exec plan to compare to XE
--USE AdventureWorks2014
USE AdventureWorks2016CTP3
GO
DBCC FREEPROCCACHE
GO
ALTER EVENT SESSION [QueryProfileXE] ON SERVER STATE = START
GO
SELECT *
FROM Sales.SalesOrderDetail sod
INNER JOIN Production.Product p ON sod.ProductID = p.ProductID
ORDER BY Style DESC
OPTION (MAXDOP 1)
GO
ALTER EVENT SESSION [QueryProfileXE] ON SERVER STATE = STOP
GO
-- After running query, get plan handle and run below to see new columns in DMV
SELECT * FROM sys.dm_exec_query_stats
WHERE plan_handle = 0x0600050006F60819800281514E02000001000000000000000000000000000000000000000000000000000000
GO
-- And to get the plan from cache
SELECT * FROM sys.dm_exec_query_plan(0x0600050006F60819800281514E02000001000000000000000000000000000000000000000000000000000000)
GO
-- After running query, get new signed query or query plan hash and run below to see new columns in DMV
SELECT * FROM sys.dm_exec_query_stats
WHERE CAST(query_hash AS BIGINT) = -5396503127623128976;
--WHERE CAST(query_plan_hash AS BIGINT) = 3230654061787450360
@@ -0,0 +1,2 @@
Each file has instructions as comments on how to run the demo. Please mind the USE clauses.
If a specific DB is needed other than AdventureworksXXXX, then you will find the Setup script in the same folder.
@@ -0,0 +1,33 @@
-- Sort Spill
-- Create xEvent session
DROP EVENT SESSION [SortSpills] ON SERVER
GO
CREATE EVENT SESSION [SortSpills] ON SERVER
ADD EVENT sqlserver.sort_warning(
ACTION(sqlserver.database_name,sqlserver.is_system,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_hash_signed,sqlserver.query_plan_hash,sqlserver.query_plan_hash_signed,sqlserver.session_nt_username,sqlserver.sql_text))
ADD TARGET package0.event_file(SET filename=N'C:\IP\Tiger\TR23\Demos\Demo 1.1 - Spills\SortSpills.xel',max_file_size=(50),max_rollover_files=(2))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO
USE AdventureWorks2014
--USE AdventureWorks2016CTP3
GO
--Execute
DBCC FREEPROCCACHE
GO
ALTER EVENT SESSION [SortSpills] ON SERVER STATE = START
GO
SELECT *
FROM Sales.SalesOrderDetail SOD
INNER JOIN Production.Product P ON SOD.ProductID = P.ProductID
ORDER BY Style
OPTION (QUERYTRACEON 9481)
GO
ALTER EVENT SESSION [SortSpills] ON SERVER STATE = STOP
GO
/*
Observe the type of Spill = 1
Means one pass over the data was enough to complete the sort in the Worktable
*/
+1
View File
@@ -0,0 +1 @@
This folder contains demos and samples for the SQL Server 2016 It Just Runs Faster Series. You can read all the blog posts at http://aka.ms/sql2016faster
@@ -21,23 +21,34 @@ Sample order processing workload that can be used for benchmarking transactional
- The max bucket_count in SQL Server 2016 is 1 billion. It is OK to have a higher row count. The benchmark performs well with bucket_count of 1 billion and row counts of 5 billion.
- There are plans to publish scripts for initial populate of the tables. Timeline is TBD.
- Scripts are also provided for corresponding disk-based tables and traditional stored procedures, to compare performance between disk-based and memory-optimized tables.
- Data size across the tables is distributed as follows:
|Table|Weight|
|----------|--------|
|Customer|1|
|Orders |5 |
|OrderLines |25 |
|Products |10 |
|PurchaseCriteria |1 |
|Fulfillment|0|
2. Run the stored procedures using the following mix.
- There are plans to make a scalable workload driver available as well. Timeline is TBD.
|Stored Procedure|Weight|
|----------|--------|
|GetOrdersByCustomerID|8|
|GetProductsByType|6|
|GetProductsPriceByPK |4 |
|ProductSelectionCriteria |2 |
|InsertOrder |10 |
|FulfillOrders |1 |
|Stored Procedure|Weight|
|----------|--------|
|GetOrdersByCustomerID|8|
|GetProductsByType|6|
|GetProductsPriceByPK |4 |
|ProductSelectionCriteria |2 |
|InsertOrder |10 |
|FulfillOrders |1 |
The recommendation is to use two different drivers:
a. Main order processing driver(s), each multi-threaded (e.g., 100 or 200 clients), and running the procedures GetOrdersByCustomerID, GetProductsByType, GetProductsPriceByPK, ProductSelectionCriteria, and InsertOrder.
a. Fulfullment driver, which runs the procedure FulfillOrders. This driver should have a single client to avoid conflicts.
- a. Main order processing driver(s), each multi-threaded (e.g., 100 or 200 clients), and running the procedures GetOrdersByCustomerID, GetProductsByType, GetProductsPriceByPK, ProductSelectionCriteria, and InsertOrder.
- b. Fulfillment driver, which runs the procedure FulfillOrders. This driver should have a single client to avoid conflicts.
## Workload description
@@ -46,7 +57,7 @@ The recommendation is to use two different drivers:
|GetOrdersByCustomerID |Read-only |Select customer info, orders, and order lines for a given customer.|
|GetProductsByType |Read-only |Select top 10 products of a given type, ordered by price.|
|GetProductsPriceByPK |Read-only |Select all products in a given ID range, ordered by price.|
|ProductSelectionCriteria |Read-only |Select top 20 products in a given ID range with the highest computed “closeness” factor against the |PurchaseCriteria|
|ProductSelectionCriteria |Read-only |Select top 20 products in a given ID range with the highest computed “closeness” factor against the PurchaseCriteria.|
|InsertOrder |Read-write |Insert a new order for a given customer with up to five order lines.|
|FulfillOrders |Read-write |Fulfill 10 oldest outstanding orders.|
@@ -2,6 +2,7 @@
This Windows Forms sample application built on .NET Framework 4.6 demonstrates the performance benefits of using SQL Server memory optimized tables and native compiled stored procedures. You can compare the performance before and after enabling In-Memory OLTP by observing the transactions/sec as well as the current CPU Usage and latches/sec.
The demo is run in this [17-minute video explaining In-Memory OLTP](https://www.youtube.com/watch?v=l5l5eophmK4) (demo is at 8:25).
<a name=about-this-sample></a>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<connectionStrings>
<!--<add name="Db" connectionString="Server=tcp:SERVER.database.windows.net,1433;Database=WideWorlsImporters;User ID=USER@SERVER;Password=PASSWORD;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"/>-->
<add name="Db" connectionString="Server=.;Database=WideWorldImporters;Integrated Security=True;Max Pool Size=250;"/>
</connectionStrings>
<appSettings>
<add key="sqlOndiskSPName" value="OnDisk.InsertCustomerOrders"/> <!--On disk Stored Procedure Name-->
<add key="sqlInMemorySPName" value="InMemory.InsertCustomerOrders"/> <!--In Memory Stored Procedure Name-->
<add key="sqlInMemoryWithCCISPName" value="InMemory.InsertCustomerOrders_CCI"/> <!--In Memory Stored Procedure Name With ColumnStore Index-->
<add key="numberOfTasks" value="250"/> <!--Number of concurrent async tasks that the Data Generator will use-->
<add key="batchSize" value="200"/> <!--Row Batch Size that every task produces-->
<add key="commandDelay" value="0"/> <!--Delay between sql commands. You can set this to 0 for max high volume workload-->
<add key="commandTimeout" value="600"/> <!--SQL Command Timeout-->
<add key="rpsFrequency" value="500"/> <!--How frequently the Data Generator Rows Per Second(RPS) is polled-->
<add key="logFileName" value="log.txt"/> <!--Log File Path-->
</appSettings>
</configuration>
@@ -0,0 +1,21 @@
using System.Threading;
using System.Threading.Tasks;
namespace DataGenerator
{
internal struct CancellableTask
{
public CancellableTask(int id, Task task, CancellationTokenSource cancellationTokenSource)
{
this.Id = id;
this.Task = task;
this.CancellationTokenSource = cancellationTokenSource;
}
public int Id { get; }
public Task Task { get; }
public CancellationTokenSource CancellationTokenSource { get; }
}
}
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D871B062-06A7-49E3-8BCD-8465B772FC52}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DataGenerator</RootNamespace>
<AssemblyName>DataGenerator</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CancellableTask.cs" />
<Compile Include="SqlDataGeneratorException.cs" />
<Compile Include="SqlDataGenerator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DataGenerator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DataGenerator")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("d871b062-06a7-49e3-8bcd-8465b772fc52")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,313 @@
//----------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
//----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Data.Sql;
using System.Data;
using System.Diagnostics;
using System.Collections.Concurrent;
using Microsoft.SqlServer.Server;
namespace DataGenerator
{
/// <summary>SqlDataGenerator is a class used for creating SQL Server sample data by using multiple Asychronous Tasks.</summary>
public class SqlDataGenerator
{
private Action<int, Exception> onException;
private ConcurrentDictionary<int, CancellableTask> tasks;
private string sqlConnectionString;
private string sqlInsertSPName;
private int sqlCommandTimeout;
private int batchSize;
private int initialNumberOfTasks;
private int delay;
private Stopwatch timer;
private int numberOfRowsInserted = 0;
protected ThreadLocal<Random> randomValue;
private bool running = false;
/// <summary>Wait Time in milliseconds between executing SqlCommands.</summary>
/// <returns>Integer</returns>
public int Delay
{
get { return delay; }
set
{
Validate(this.batchSize, this.initialNumberOfTasks, value);
delay = value;
}
}
/// <summary>The row count of the sample data batch that every task generates.</summary>
/// <returns>Integer</returns>
public int BatchSize
{
get { return batchSize; }
set
{
Validate(value, this.initialNumberOfTasks, this.delay);
batchSize = value;
}
}
/// <summary>Rows (inserted or updated) per second.</summary>
/// <returns>Double</returns>
public double Rps => (double)this.numberOfRowsInserted / this.timer.Elapsed.TotalSeconds;
/// <summary>The number of current active tasks.</summary>
/// <returns>Integer</returns>
public int RunningTasks => this.tasks.Count();
/// <summary>Running Status</summary>
/// <returns>Bool</returns>
public bool IsRunning => this.running;
/// <summary>Creates a new instance of the SqlDataGenerator Class.</summary>
/// <param name="sqlConnectionString">The sqlserver connectionString. Example: "Data Source=.;Initial Catalog=DbName;Integrated Security=True"</param>
/// <param name="sqlInsertSPName">The Insert Orders sqlserver stored procedure. Example: "InsertOrdersSP". </param>
/// <param name="sqlCommandTimeout">The sqlserver command timeout. Example: 600</param>
/// <param name="initialNumberOfTasks">The number of concurrent tasks. Example: 5. Note that every task 1.Creates and opens a new sql connection 2.Creates sample data and 3.Executes the sql stored procedure passed in sqlStoredProcedureName endless times until stopped by the user.</param>
/// <param name="delayInMilliseconds">Delay in Millisecods betweeen Sql Commands. Example. 100</param>
/// <param name="batchSize">The row count of the batch size to be used by every task. Example: 200</param>
/// <param name="onException">Exception call back method with TaskId(int) and exception(Exception). Example: ExceptionCallback</param>
public SqlDataGenerator(
string sqlConnectionString,
string sqlInsertSPName,
int sqlCommandTimeout,
int initialNumberOfTasks,
int delayInMilliseconds,
int batchSize,
Action<int, Exception> onException)
{
this.sqlConnectionString = sqlConnectionString;
this.sqlInsertSPName = sqlInsertSPName;
this.sqlCommandTimeout = sqlCommandTimeout;
this.onException = onException;
this.tasks = new ConcurrentDictionary<int, CancellableTask>();
this.randomValue = new ThreadLocal<Random>(() => new Random(Guid.NewGuid().GetHashCode()));
this.initialNumberOfTasks = initialNumberOfTasks;
this.delay = delayInMilliseconds;
this.batchSize = batchSize;
Validate(this.batchSize, this.initialNumberOfTasks, this.delay);
}
/// <summary>Creates and Starts all the tasks asynchronously. Note that every task 1.Creates and opens a new sql connection 2.Creates a batch of BatchSize sample data and 3.Executes the sql stored procedure passed in sqlStoredProcedureName endless times until stopped by the user.</summary>
/// <returns>Task</returns>
public async Task RunAsync()
{
if (this.running)
{
return;
}
timer = Stopwatch.StartNew();
await this.RunAsync(this.initialNumberOfTasks);
}
/// <summary>Stops all tasks asynchronously.</summary>
/// <returns>Task</returns>
public async Task StopAsync()
{
await this.StopAsync(this.RunningTasks);
}
/// <summary>Restarts the Rows/Second Counter. This is called internally every time the input is changed.</summary>
/// <returns>void</returns>
public void RpsReset()
{
if (running)
{
this.timer.Restart();
this.numberOfRowsInserted = 0;
}
}
/// <summary>Updates the number of tasks that the DataGenerator is using.</summary>
/// <returns>Task</returns>
/// <remarks></remarks>
/// <param name="numberOfTasks">The number of Tasks to start/stop depending of the number of tasks currently running.</param>
public async Task UpdateTasksAsync(int numberOfTasks)
{
int diff = numberOfTasks - this.RunningTasks;
if (!running || diff == 0)
{
this.initialNumberOfTasks = numberOfTasks;
return;
}
if (diff < 0)
{
await this.StopAsync(-diff);
}
else
{
await this.RunAsync(diff);
}
}
/// <summary>InsertOrdersAsync(int taskId, CancellationToken token)</summary>
/// <returns>Task</returns>
/// <remarks>Every Task creates a new sql connection, creates a new sqlcommand, create a batch of random numbers, and executes indefinetely until stopped by the user.</remarks>
/// <param name="taskId">The taskId</param>
/// <param name="token">The task's CancellationToken</param>
private async Task InsertOrdersAsync(int taskId, CancellationToken token)
{
int size = this.BatchSize;
int personId;
var orderTable = new DataTable("Orders");
var orderLinesTable = new DataTable("OrderLines");
using (SqlConnection connection = new SqlConnection(this.sqlConnectionString))
{
await connection.OpenAsync(token);
using (var insertCommand = connection.CreateCommand())
{
insertCommand.CommandType = CommandType.StoredProcedure;
insertCommand.CommandTimeout = this.sqlCommandTimeout;
insertCommand.CommandText = this.sqlInsertSPName;
insertCommand.Parameters.Add("@Orders", SqlDbType.Structured);
insertCommand.Parameters.Add("@OrderLines", SqlDbType.Structured);
insertCommand.Parameters.Add("@OrdersCreatedByPersonID", SqlDbType.Int);
insertCommand.Parameters.Add("@SalespersonPersonID", SqlDbType.Int);
while (!token.IsCancellationRequested)
{
using (var selectCommand = connection.CreateCommand())
{
var da = new SqlDataAdapter(selectCommand);
var rnd = new Random();
personId = rnd.Next(1,1000); // Random person Id
// Get Order
selectCommand.CommandText = "SELECT TOP(1) 1 AS OrderReference, c.CustomerID, c.PrimaryContactPersonID AS ContactPersonID, CAST(DATEADD(day, 1, SYSDATETIME()) AS date) AS ExpectedDeliveryDate, CAST(FLOOR(RAND() * 10000) + 1 AS nvarchar(20)) AS CustomerPurchaseOrderNumber, CAST(0 AS bit) AS IsUndersupplyBackordered, N'Auto-generated' AS Comments, c.DeliveryAddressLine1 + N', ' + c.DeliveryAddressLine2 AS DeliveryInstructions FROM Sales.Customers AS c ORDER BY NEWID();";
orderTable = new DataTable("Orders");
da.Fill(orderTable);
// Get Order Lines
selectCommand.CommandText = "SELECT TOP(" + size + ") 1 AS OrderReference, si.StockItemID, si.StockItemName AS [Description], FLOOR(RAND() * 10) + 1 AS Quantity FROM Warehouse.StockItems AS si WHERE IsChillerStock = 0 ORDER BY NEWID()";
orderLinesTable = new DataTable("OrderLines");
da.Fill(orderLinesTable);
}
insertCommand.Parameters["@Orders"].Value = orderTable;
insertCommand.Parameters["@OrderLines"].Value = orderLinesTable;
insertCommand.Parameters["@OrdersCreatedByPersonID"].Value = personId;
insertCommand.Parameters["@SalespersonPersonID"].Value = personId;
await insertCommand.ExecuteNonQueryAsync(token);
Interlocked.Add(ref this.numberOfRowsInserted, size);
await Task.Delay(this.Delay, token);
orderTable.Clear();
orderLinesTable.Clear();
}
}
}
}
/// <summary>StopAsync(int numberOfTasksToStop)</summary>
/// <returns>Task</returns>
/// <param name="numberOfTasksToStop">The number of Tasks to stop.</param>
private async Task StopAsync(int numberOfTasksToStop)
{
// TODO: Lock
if (numberOfTasksToStop >= this.RunningTasks) { this.running = false; }
numberOfTasksToStop = Math.Min(numberOfTasksToStop, this.RunningTasks);
List<CancellableTask> cancellableTasksToKill = this.tasks.Take(numberOfTasksToStop).Select(kv => kv.Value).ToList();
foreach (CancellableTask cancellableTask in cancellableTasksToKill)
{
cancellableTask.CancellationTokenSource.Cancel();
}
await Task.WhenAll(cancellableTasksToKill.Select(c => c.Task));
}
/// <summary>RunAsync(int numberOfTasks)</summary>
/// <returns>Task</returns>
/// <param name="numberOfTasks">The number of Tasks to start/stop depending of the number of tasks currently running.</param>
private async Task RunAsync(int numberOfTasks)
{
for (int i = 0; i < numberOfTasks; i++)
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
int taskId = i;
Task task = Task.Factory.StartNew(
async () => await this.InsertOrdersAsync(taskId, tokenSource.Token).ContinueWith(t => CleanupTask(taskId, t)),
tokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default).Unwrap();
tasks.TryAdd(taskId, new CancellableTask(taskId, task, tokenSource));
}
this.running = true;
await Task.WhenAll(this.tasks.Values.Select(t => t.Task));
}
/// <summary>CleanupTask(int taskId, Task task)</summary>
/// <returns>void</returns>
/// <remarks></remarks>
/// <param name="taskId">The taskId</param>
/// <param name="task">The actual Task</param>
private void CleanupTask(int taskId, Task task)
{
CancellableTask cancellableTask;
bool succeeded = this.tasks.TryRemove(taskId, out cancellableTask);
if (task.IsFaulted && !cancellableTask.CancellationTokenSource.IsCancellationRequested)
{
this.onException(taskId, task.Exception?.InnerException);
}
}
/// <summary>Validate(int batchSize, int tasks, int delay)</summary>
/// <param name="batchSize">The Batch Size</param>
/// <param name="tasks">The number Of Tasks</param>
/// <param name="delay">Teh Delay</param>
private void Validate(int batchSize, int tasks, int delay)
{
// Validate
if (batchSize <= 0)
{
throw new SqlDataGeneratorException("The Batch Size cannot be less or equal to zero.");
}
if (tasks <= 0)
{
throw new SqlDataGeneratorException("Number Of Tasks cannot be less or equal to zero.");
}
if (delay < 0)
{
throw new SqlDataGeneratorException("Delay cannot be less than zero");
}
// Reset Rps
RpsReset();
}
}
}
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataGenerator
{
public class SqlDataGeneratorException : Exception
{
public SqlDataGeneratorException()
:base()
{
}
public SqlDataGeneratorException(string message)
:base(message)
{
}
public SqlDataGeneratorException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}
@@ -0,0 +1,95 @@
# Wide World Importers - Sales Orders
This Windows Forms sample application built on .NET Framework 4.6 demonstrates the performance benefits of using SQL Server memory optimized tables and native compiled stored procedures. You can compare the performance before and after enabling In-Memory OLTP by observing the transactions/sec as well as the current CPU Usage and latches/sec.
### Contents
[About this sample](#about-this-sample)<br/>
[Before you begin](#before-you-begin)<br/>
[Run this sample](#run-this-sample)<br/>
[Sample details](#sample-details)<br/>
[Disclaimers](#disclaimers)<br/>
[Related links](#related-links)<br/>
<a name=about-this-sample></a>
## About this sample
1. **Applies to:** SQL Server 2016 (or higher) Enterprise / Developer / Evaluation Edition, Azure SQL Database
2. **Key features:**
- Memory Optimized Tables and Table valued Parameters (TVPs)
- Natively Compiled Stored Procedures
- Clustered Columnstore Index (CCI)
3. **Workload:** Data Ingestion for Wide World Importers (Customer Orders table)
4. **Programming Language:** .NET C#, T-SQL
5. **Authors:** Perry Skountrianos [perrysk-msft]
<a name=before-you-begin></a>
## Before you begin
To run this sample, you need the following prerequisites.
**Software prerequisites:**
1. SQL Server 2016 (or higher) or an Azure SQL Database
2. Visual Studio 2015 (or higher) with the latest SSDT installed
3. Wide World Importers Database restored
**Azure prerequisites:**
1. Permission to create an Azure SQL Database
<a name=run-this-sample></a>
## Run this sample
1. Clone this repository using Git for Windows (http://www.git-scm.com/), or download the zip file.
2. From Visual Studio, open the **WWI-SalesOrders.sln** file from the root directory.
3. In Visual Studio Build menu, select **Build Solution** (or Press F6).
4. Modify the **App.config Settings** (located in the **Solution Items** solution folder)
- **Db**: SQL Server connectionString. Currently it is configured to connect to the local default SQL Server Instance using Integrated Security.
5. Open the CustomerOrders.sql SQL script (located under scripts) and run it against the World Wide Importers DB.
5. Build the app and run it. Do not use the debugger, as that will slow down the app.
6. You can see the performance gains by switching to the In-Memory radio button option.
<a name=sample-details></a>
The perf gains from In-Memory OLTP as shown by the load generation app depend on two factors:
- Hardware
- more cores => higher perf gain
- slower log IO => lower perf gain
- Configuration settings in the load generator
- more rows per transaction => higher perf gain
- more reads per write => lower perf gain
## Sample details
**High Level Description**
This code sample demonstrates the performance gains of SQL Server 2016 (or higher) In-Memory tables and natively compiled Stored procedures.
![Alt text](Screenshots/OnDisk.png "Using On Disk Objects")
![Alt text](Screenshots/InMemory.png "Using In Memory Objects")
![Alt text](Screenshots/InMemoryWith CCI.png "Using In Memory with CCI")
<a name=disclaimers></a>
## Disclaimers
The code included in this sample is not intended to be a set of best practices on how to build scalable enterprise grade applications. This is beyond the scope of this quick start sample.
<a name=related-links></a>
## Related Links
<!-- Links to more articles. Remember to delete "en-us" from the link path. -->
For more information, see these articles:
- [In-Memory OLTP (In-Memory Optimization)] (https://msdn.microsoft.com/en-us/library/dn133186.aspx)
- [OLTP and database management] (https://www.microsoft.com/en-us/server-cloud/solutions/oltp-database-management.aspx)
- [SQL Server 2016 Temporal Tables] (https://msdn.microsoft.com/en-us/library/dn935015.aspx)
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,280 @@
namespace Client
{
partial class FrmMain
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.DataPoint dataPoint1 = new System.Windows.Forms.DataVisualization.Charting.DataPoint(0D, 0D);
this.bottomToolStrip = new System.Windows.Forms.ToolStrip();
this.lblTasksTitle = new System.Windows.Forms.ToolStripLabel();
this.lblTasksValue = new System.Windows.Forms.ToolStripLabel();
this.tss_1 = new System.Windows.Forms.ToolStripSeparator();
this.lblBatchSizeTitle = new System.Windows.Forms.ToolStripLabel();
this.lblBatchSizeValue = new System.Windows.Forms.ToolStripLabel();
this.tss_2 = new System.Windows.Forms.ToolStripSeparator();
this.lblRpsTitle = new System.Windows.Forms.ToolStripLabel();
this.lblRpsValue = new System.Windows.Forms.ToolStripLabel();
this.Start = new System.Windows.Forms.Button();
this.Stop = new System.Windows.Forms.Button();
this.RpsChart = new System.Windows.Forms.DataVisualization.Charting.Chart();
this.rpsTimer = new System.Windows.Forms.Timer(this.components);
this.mainTimer = new System.Windows.Forms.Timer(this.components);
this.InMemoryRadioButton = new System.Windows.Forms.RadioButton();
this.OnDiskRadioButton = new System.Windows.Forms.RadioButton();
this.InMemoryWithCSIRadioButton = new System.Windows.Forms.RadioButton();
this.bottomToolStrip.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.RpsChart)).BeginInit();
this.SuspendLayout();
//
// bottomToolStrip
//
this.bottomToolStrip.BackColor = System.Drawing.Color.White;
this.bottomToolStrip.Dock = System.Windows.Forms.DockStyle.Bottom;
this.bottomToolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.lblTasksTitle,
this.lblTasksValue,
this.tss_1,
this.lblBatchSizeTitle,
this.lblBatchSizeValue,
this.tss_2,
this.lblRpsTitle,
this.lblRpsValue});
this.bottomToolStrip.Location = new System.Drawing.Point(0, 300);
this.bottomToolStrip.Name = "bottomToolStrip";
this.bottomToolStrip.Size = new System.Drawing.Size(851, 43);
this.bottomToolStrip.TabIndex = 0;
this.bottomToolStrip.Text = "toolStrip1";
//
// lblTasksTitle
//
this.lblTasksTitle.ForeColor = System.Drawing.Color.Gray;
this.lblTasksTitle.Name = "lblTasksTitle";
this.lblTasksTitle.Size = new System.Drawing.Size(52, 40);
this.lblTasksTitle.Text = "Threads:";
//
// lblTasksValue
//
this.lblTasksValue.Name = "lblTasksValue";
this.lblTasksValue.Size = new System.Drawing.Size(13, 40);
this.lblTasksValue.Text = "0";
//
// tss_1
//
this.tss_1.Name = "tss_1";
this.tss_1.Size = new System.Drawing.Size(6, 43);
//
// lblBatchSizeTitle
//
this.lblBatchSizeTitle.ForeColor = System.Drawing.Color.Gray;
this.lblBatchSizeTitle.Name = "lblBatchSizeTitle";
this.lblBatchSizeTitle.Size = new System.Drawing.Size(98, 40);
this.lblBatchSizeTitle.Text = "Rows Per Thread:";
//
// lblBatchSizeValue
//
this.lblBatchSizeValue.Name = "lblBatchSizeValue";
this.lblBatchSizeValue.Size = new System.Drawing.Size(13, 40);
this.lblBatchSizeValue.Text = "0";
//
// tss_2
//
this.tss_2.Name = "tss_2";
this.tss_2.Size = new System.Drawing.Size(6, 43);
//
// lblRpsTitle
//
this.lblRpsTitle.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
this.lblRpsTitle.ForeColor = System.Drawing.Color.DimGray;
this.lblRpsTitle.Name = "lblRpsTitle";
this.lblRpsTitle.Size = new System.Drawing.Size(112, 40);
this.lblRpsTitle.Text = "Rows/sec inserted:";
//
// lblRpsValue
//
this.lblRpsValue.Font = new System.Drawing.Font("Segoe UI", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblRpsValue.ForeColor = System.Drawing.Color.Red;
this.lblRpsValue.Name = "lblRpsValue";
this.lblRpsValue.Size = new System.Drawing.Size(33, 40);
this.lblRpsValue.Text = "0";
//
// Start
//
this.Start.FlatAppearance.BorderColor = System.Drawing.Color.Silver;
this.Start.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.Start.Location = new System.Drawing.Point(717, 291);
this.Start.Name = "Start";
this.Start.Size = new System.Drawing.Size(105, 40);
this.Start.TabIndex = 2;
this.Start.Text = "Start";
this.Start.UseVisualStyleBackColor = true;
this.Start.Click += new System.EventHandler(this.Start_Click);
//
// Stop
//
this.Stop.Enabled = false;
this.Stop.FlatAppearance.BorderColor = System.Drawing.Color.Silver;
this.Stop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.Stop.Location = new System.Drawing.Point(606, 291);
this.Stop.Name = "Stop";
this.Stop.Size = new System.Drawing.Size(105, 40);
this.Stop.TabIndex = 3;
this.Stop.Text = "Stop";
this.Stop.UseVisualStyleBackColor = true;
this.Stop.Click += new System.EventHandler(this.Stop_Click);
//
// RpsChart
//
this.RpsChart.BackColor = System.Drawing.Color.Transparent;
this.RpsChart.BorderlineColor = System.Drawing.Color.Black;
chartArea1.AxisX.IntervalType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Seconds;
chartArea1.AxisX.LabelAutoFitMaxFontSize = 8;
chartArea1.AxisX.LineColor = System.Drawing.Color.DarkGray;
chartArea1.AxisX.MajorGrid.Enabled = false;
chartArea1.AxisX.MajorGrid.Interval = 0D;
chartArea1.AxisX.MajorGrid.IntervalOffset = 0D;
chartArea1.AxisX.MajorGrid.IntervalType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Auto;
chartArea1.AxisX.MajorTickMark.Enabled = false;
chartArea1.AxisX.Maximum = 100D;
chartArea1.AxisX.Minimum = 0D;
chartArea1.AxisY.LabelAutoFitMaxFontSize = 8;
chartArea1.AxisY.LineColor = System.Drawing.Color.DarkGray;
chartArea1.AxisY.MajorGrid.Enabled = false;
chartArea1.AxisY.Minimum = 0D;
chartArea1.BackColor = System.Drawing.Color.Transparent;
chartArea1.Name = "Chart";
this.RpsChart.ChartAreas.Add(chartArea1);
legend1.BackColor = System.Drawing.Color.Transparent;
legend1.Enabled = false;
legend1.ForeColor = System.Drawing.Color.Maroon;
legend1.Name = "Legend1";
this.RpsChart.Legends.Add(legend1);
this.RpsChart.Location = new System.Drawing.Point(0, 0);
this.RpsChart.Name = "RpsChart";
this.RpsChart.Palette = System.Windows.Forms.DataVisualization.Charting.ChartColorPalette.None;
series1.ChartArea = "Chart";
series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.SplineArea;
series1.Color = System.Drawing.Color.DarkGray;
series1.Font = new System.Drawing.Font("Microsoft Sans Serif", 6F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
series1.Legend = "Legend1";
series1.LegendText = "sadsaDS";
series1.MarkerBorderWidth = 3;
series1.Name = "RPS";
series1.Points.Add(dataPoint1);
this.RpsChart.Series.Add(series1);
this.RpsChart.Size = new System.Drawing.Size(847, 262);
this.RpsChart.TabIndex = 102;
this.RpsChart.Text = "Rows / Sec";
//
// rpsTimer
//
this.rpsTimer.Interval = 300;
this.rpsTimer.Tick += new System.EventHandler(this.rpsTimer_Tick);
//
// InMemoryRadioButton
//
this.InMemoryRadioButton.AutoSize = true;
this.InMemoryRadioButton.ForeColor = System.Drawing.Color.Black;
this.InMemoryRadioButton.Location = new System.Drawing.Point(553, 258);
this.InMemoryRadioButton.Name = "InMemoryRadioButton";
this.InMemoryRadioButton.Size = new System.Drawing.Size(74, 17);
this.InMemoryRadioButton.TabIndex = 105;
this.InMemoryRadioButton.Text = "In Memory";
this.InMemoryRadioButton.UseVisualStyleBackColor = true;
//
// OnDiskRadioButton
//
this.OnDiskRadioButton.AutoSize = true;
this.OnDiskRadioButton.Checked = true;
this.OnDiskRadioButton.Location = new System.Drawing.Point(484, 258);
this.OnDiskRadioButton.Name = "OnDiskRadioButton";
this.OnDiskRadioButton.Size = new System.Drawing.Size(63, 17);
this.OnDiskRadioButton.TabIndex = 104;
this.OnDiskRadioButton.TabStop = true;
this.OnDiskRadioButton.Text = "On Disk";
this.OnDiskRadioButton.UseVisualStyleBackColor = true;
//
// InMemoryWithCSIRadioButton
//
this.InMemoryWithCSIRadioButton.AutoSize = true;
this.InMemoryWithCSIRadioButton.ForeColor = System.Drawing.Color.Black;
this.InMemoryWithCSIRadioButton.Location = new System.Drawing.Point(633, 258);
this.InMemoryWithCSIRadioButton.Name = "InMemoryWithCSIRadioButton";
this.InMemoryWithCSIRadioButton.Size = new System.Drawing.Size(191, 17);
this.InMemoryWithCSIRadioButton.TabIndex = 106;
this.InMemoryWithCSIRadioButton.Text = "In Memory With ColumnStore Index";
this.InMemoryWithCSIRadioButton.UseVisualStyleBackColor = true;
//
// FrmMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(851, 343);
this.Controls.Add(this.InMemoryWithCSIRadioButton);
this.Controls.Add(this.InMemoryRadioButton);
this.Controls.Add(this.OnDiskRadioButton);
this.Controls.Add(this.RpsChart);
this.Controls.Add(this.Stop);
this.Controls.Add(this.Start);
this.Controls.Add(this.bottomToolStrip);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "FrmMain";
this.Text = "Data Generator Client";
this.bottomToolStrip.ResumeLayout(false);
this.bottomToolStrip.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.RpsChart)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ToolStrip bottomToolStrip;
private System.Windows.Forms.ToolStripLabel lblTasksTitle;
private System.Windows.Forms.ToolStripLabel lblTasksValue;
private System.Windows.Forms.ToolStripSeparator tss_1;
private System.Windows.Forms.ToolStripLabel lblBatchSizeTitle;
private System.Windows.Forms.ToolStripLabel lblBatchSizeValue;
private System.Windows.Forms.ToolStripSeparator tss_2;
private System.Windows.Forms.Button Start;
private System.Windows.Forms.Button Stop;
private System.Windows.Forms.DataVisualization.Charting.Chart RpsChart;
private System.Windows.Forms.ToolStripLabel lblRpsTitle;
private System.Windows.Forms.ToolStripLabel lblRpsValue;
private System.Windows.Forms.Timer rpsTimer;
private System.Windows.Forms.Timer mainTimer;
private System.Windows.Forms.RadioButton InMemoryRadioButton;
private System.Windows.Forms.RadioButton OnDiskRadioButton;
private System.Windows.Forms.RadioButton InMemoryWithCSIRadioButton;
}
}
@@ -0,0 +1,189 @@
/*----------------------------------------------------------------------------------
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
----------------------------------------------------------------------------------
The example companies, organizations, products, domain names,
e-mail addresses, logos, people, places, and events depicted
herein are fictitious. No association with any real company,
organization, product, domain name, email address, logo, person,
places, or events is intended or should be inferred.
*/
using DataGenerator;
using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace Client
{
public partial class FrmMain : Form
{
private SqlDataGenerator dataGenerator;
private string connection;
private string spName;
private string logFileName;
private int tasks;
private int batchSize;
private int delay;
private int commandTimeout;
private int rpsFrequency;
private int rpsChartTime = 0;
public FrmMain()
{
InitializeComponent();
}
private void ExceptionCallback(int taskId, Exception exception)
{
HandleException(exception, taskId);
}
private void HandleException(Exception exception, int? taskId = null)
{
// Uncomment for debugging
string ex = taskId?.ToString() + " - " + exception.Message + (exception.InnerException != null ? "\n\nInner Exception\n" + exception.InnerException : "");
using (StreamWriter w = File.AppendText(logFileName)) { w.WriteLine("\r\n{0}: {1}", DateTime.Now, ex); }
}
private async void Start_Click(object sender, EventArgs e)
{
try
{
this.rpsTimer.Start();
this.Stop.Enabled = true;
this.Stop.Update();
this.Start.Enabled = false;
this.Start.Update();
this.OnDiskRadioButton.Enabled = false;
this.InMemoryRadioButton.Enabled = false;
this.InMemoryWithCSIRadioButton.Enabled = false;
Init();
await this.dataGenerator.RunAsync();
}
catch (Exception exception) { HandleException(exception); }
}
private async void Stop_Click(object sender, EventArgs e)
{
try
{
//this.UpdateChart(-1);
this.rpsTimer.Stop();
//this.lblRpsValue.Text = "0";
//this.lblTasksValue.Text = "0";
this.Stop.Enabled = false;
this.Stop.Update();
this.Start.Enabled = true;
this.Start.Update();
this.OnDiskRadioButton.Enabled = true;
this.InMemoryRadioButton.Enabled = true;
this.InMemoryWithCSIRadioButton.Enabled = true;
await this.dataGenerator.StopAsync();
this.dataGenerator.RpsReset();
}
catch (Exception exception) { HandleException(exception); }
}
private void UpdateChart(double rps)
{
if (rps >= 0)
{
rpsChartTime++;
if (rpsChartTime > this.RpsChart.ChartAreas[0].AxisX.Maximum)
{
this.RpsChart.ChartAreas[0].AxisX.Maximum += 100;
}
this.RpsChart.Series[0].Points.Add(new DataPoint(rpsChartTime, rps));
}
else
{
this.RpsChart.Series[0].Points.Clear();
rpsChartTime = 0;
}
this.RpsChart.Update();
}
private void Init()
{
try
{
// Read Config Settings
this.connection = ConfigurationManager.ConnectionStrings["Db"].ConnectionString;
if (OnDiskRadioButton.Checked)
{
this.spName = ConfigurationManager.AppSettings["sqlOndiskSPName"];
}
else if (InMemoryRadioButton.Checked)
{
this.spName = ConfigurationManager.AppSettings["sqlInMemorySPName"];
}
else
{
this.spName = ConfigurationManager.AppSettings["sqlInMemoryWithCCISPName"];
}
this.logFileName = ConfigurationManager.AppSettings["logFileName"];
this.tasks = int.Parse(ConfigurationManager.AppSettings["numberOfTasks"]);
this.batchSize = int.Parse(ConfigurationManager.AppSettings["batchSize"]);
this.delay = int.Parse(ConfigurationManager.AppSettings["commandDelay"]);
this.commandTimeout = int.Parse(ConfigurationManager.AppSettings["commandTimeout"]);
this.rpsFrequency = int.Parse(ConfigurationManager.AppSettings["rpsFrequency"]);
this.dataGenerator = new SqlDataGenerator(this.connection, this.spName, this.commandTimeout, this.tasks, this.delay, this.batchSize, this.ExceptionCallback);
// Initialize Timers
this.rpsTimer.Interval = this.rpsFrequency;
// Initialize Labels
this.lblTasksValue.Text = string.Format("{0:#,#}", this.tasks).ToString();
this.lblBatchSizeValue.Text = string.Format("{0:#,#}", this.batchSize).ToString();
if (batchSize <= 0) throw new SqlDataGeneratorException("The Batch Size cannot be less or equal to zero.");
if (tasks <= 0) throw new SqlDataGeneratorException("Number Of Tasks cannot be less or equal to zero.");
if (delay < 0) throw new SqlDataGeneratorException("Delay cannot be less than zero");
}
catch (Exception exception) { HandleException(exception); }
}
private void rpsTimer_Tick(object sender, EventArgs e)
{
try
{
this.lblTasksValue.Text = this.dataGenerator.RunningTasks.ToString();
double rps = this.dataGenerator.Rps;
if (dataGenerator.IsRunning)
{
if (this.dataGenerator.RunningTasks == 0) return;
if (rps > 0)
{
this.lblRpsValue.Text = string.Format("{0:#,#}", rps).ToString();
UpdateChart(rps);
}
}
}
catch (Exception exception) { HandleException(exception); }
}
}
}
@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="bottomToolStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="rpsTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>159, 17</value>
</metadata>
<metadata name="mainTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>258, 17</value>
</metadata>
</root>
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Client
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FrmMain());
}
}
}
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Client")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Client")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6c0e1820-a10b-47da-b806-939cbcd0dd39")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Client.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Client.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Client.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6C0E1820-A10B-47DA-B806-939CBCD0DD39}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Client</RootNamespace>
<AssemblyName>Client</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>x64</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Windows.Forms.DataVisualization" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="FrmMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FrmMain.Designer.cs">
<DependentUpon>FrmMain.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="FrmMain.resx">
<DependentUpon>FrmMain.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="..\App.config">
<Link>App.config</Link>
<SubType>Designer</SubType>
</None>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DataGenerator\DataGenerator.csproj">
<Project>{d871b062-06a7-49e3-8bcd-8465b772fc52}</Project>
<Name>DataGenerator</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
+42
View File
@@ -0,0 +1,42 @@
# SQLVDI
This folder contains the latest files and samples required to build a SQL Server VDI based backup/restore application.
### Files available
1. vdi.h
2. vdierror.h
3. vdiguid.h
A new **VDC_Complete** command was added to SQLVDI that indicates SQL Server has completed sending data to the VDI client. Therefore, the VDI client will be able to finish the backup before it sends response to SQL Server.
More details about this improvement in the SQLVDI protocol can be found in [KB3188454: Enhance VDI Protocol with VDC_Complete command in SQL Server] (https://support.microsoft.com/en-us/kb/3188454)
The following implementations have to be applied to your VDI client:
1. Request the new VDI feature VDF_RequestComplete.
2. If SQL Server supports the VDC_Complete command, it will return a not NULL response.
3. Otherwise, it would return a NULL response for the requested feature.
The code sample here shows how to request the feature: 
```
m_pvdiComponents->m_pvdConfig->features = VDF_RequestComplete;
printf("Requested features to SQL Server: 0x{0:X}", m_pvdiComponents->m_pvdConfig->features);
```
Determine whether the SQL Server supports the new VDC_Complete command by using the GetConfiguration function.
```
hr = m_pvdiComponents->m_pvdDeviceSet->GetConfiguration(timeout, m_pvdiComponents->m_pvdConfig);
if (!(m_pvdiComponents->m_pvdConfig->features & VDF_CompleteEnabled))
{
printf("Server does not support VDC_Complete.");
return VD_E_NOTSUPPORTED;
}
```
When you process the VDI messages that are fetched by the GetCommand function, add an additional case statement to process the VDC_Complete command.
```
case VDC_Complete:
// Close the media and ensure that book keeping is completed.
backupMedia->Close();
completionCode = ERROR_SUCCESS;
break;
```
File diff suppressed because it is too large Load Diff
+78
View File
@@ -0,0 +1,78 @@
#ifndef VDIERROR_H_
#define VDIERROR_H_
//****************************************************************************
// Copyright (c) Microsoft Corporation.
//
// vdierror.h
//
// Purpose:
// Declare the error codes emitted by the virtual device interface.
//
//****************************************************************************
//---------------------------------------------------------------------------------------
// Error code handling will be done in standard COM fashion:
//
// an HRESULT is returned and the caller can use
// SUCCEEDED(code) or FAILED(code) to determine
// if the function failed or not.
//
// Form an error code mask.
// All VDI errors have 0x8077 as prefix.
//
#define VD_ERROR(code) MAKE_HRESULT(SEVERITY_ERROR, 0x77, code)
// The object was not open
//
#define VD_E_NOTOPEN VD_ERROR( 2 ) /* 0x80770002 */
// The api was waiting and the timeout interval had elapsed.
//
#define VD_E_TIMEOUT VD_ERROR( 3 ) /* 0x80770003 */
// An abort request is preventing anything except termination actions.
//
#define VD_E_ABORT VD_ERROR( 4 ) /* 0x80770004 */
// Failed to create security environment.
//
#define VD_E_SECURITY VD_ERROR( 5 ) /* 0x80770005 */
// An invalid parameter was supplied
//
#define VD_E_INVALID VD_ERROR( 6 ) /* 0x80770006 */
// Failed to recognize the SQL Server instance name
//
#define VD_E_INSTANCE_NAME VD_ERROR( 7 ) /* 0x80770007 */
// The requested configuration is invalid
//
#define VD_E_NOTSUPPORTED VD_ERROR( 9 ) /* 0x80770009 */
// Out of memory
//
#define VD_E_MEMORY VD_ERROR( 10 ) /* 0x8077000a */
// Unexpected internal error
//
#define VD_E_UNEXPECTED VD_ERROR (11) /* 0x8077000b */
// Protocol error
//
#define VD_E_PROTOCOL VD_ERROR (12) /* 0x8077000c */
// All devices are open
//
#define VD_E_OPEN VD_ERROR (13) /* 0x8077000d */
// the object is now closed
//
#define VD_E_CLOSE VD_ERROR (14) /* 0x8077000e */
// the resource is busy
//
#define VD_E_BUSY VD_ERROR (15) /* 0x8077000f */
#endif
+198
View File
@@ -0,0 +1,198 @@
/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
/* link this file in with the server and any clients */
/* File created by MIDL compiler version 7.00.0408 */
/* at Tue Sep 28 18:18:04 2004
*/
/* Compiler settings for vdi.idl:
Oicf, W1, Zp8, env=Win32 (32b run)
protocol : dce , ms_ext, c_ext, robust
error checks: allocation ref bounds_check enum stub_data
VC __declspec() decoration level:
__declspec(uuid()), __declspec(selectany), __declspec(novtable)
DECLSPEC_UUID(), MIDL_INTERFACE()
*/
//@@MIDL_FILE_HEADING( )
#if !defined(_M_IA64) && !defined(_M_AMD64)
#pragma warning( disable: 4049 ) /* more than 64k source lines */
#ifdef __cplusplus
extern "C"{
#endif
#include <rpc.h>
#include <rpcndr.h>
#ifdef _MIDL_USE_GUIDDEF_
#ifndef INITGUID
#define INITGUID
#include <guiddef.h>
#undef INITGUID
#else
#include <guiddef.h>
#endif
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
#else // !_MIDL_USE_GUIDDEF_
#ifndef __IID_DEFINED__
#define __IID_DEFINED__
typedef struct _IID
{
unsigned long x;
unsigned short s1;
unsigned short s2;
unsigned char c[8];
} IID;
#endif // __IID_DEFINED__
#ifndef CLSID_DEFINED
#define CLSID_DEFINED
typedef IID CLSID;
#endif // CLSID_DEFINED
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
#endif !_MIDL_USE_GUIDDEF_
MIDL_DEFINE_GUID(IID, IID_IClientVirtualDevice,0x40700424,0x0080,0x11d2,0x85,0x1f,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IClientVirtualDeviceSet,0x40700425,0x0080,0x11d2,0x85,0x1f,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IClientVirtualDeviceSet2,0xd0e6eb07,0x7a62,0x11d2,0x85,0x73,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IServerVirtualDevice,0xb5e7a131,0xa7bd,0x11d1,0x84,0xc2,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IServerVirtualDeviceSet,0xb5e7a132,0xa7bd,0x11d1,0x84,0xc2,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IServerVirtualDeviceSet2,0xAECBD0D6,0x24C6,0x11d3,0x85,0xB7,0x00,0xC0,0x4F,0xC2,0x17,0x59);
#undef MIDL_DEFINE_GUID
#ifdef __cplusplus
}
#endif
#endif /* !defined(_M_IA64) && !defined(_M_AMD64)*/
/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
/* link this file in with the server and any clients */
/* File created by MIDL compiler version 7.00.0408 */
/* at Tue Sep 28 18:18:04 2004
*/
/* Compiler settings for vdi.idl:
Oicf, W1, Zp8, env=Win64 (32b run,appending)
protocol : dce , ms_ext, c_ext, robust
error checks: allocation ref bounds_check enum stub_data
VC __declspec() decoration level:
__declspec(uuid()), __declspec(selectany), __declspec(novtable)
DECLSPEC_UUID(), MIDL_INTERFACE()
*/
//@@MIDL_FILE_HEADING( )
#if defined(_M_IA64) || defined(_M_AMD64)
#pragma warning( disable: 4049 ) /* more than 64k source lines */
#ifdef __cplusplus
extern "C"{
#endif
#include <rpc.h>
#include <rpcndr.h>
#ifdef _MIDL_USE_GUIDDEF_
#ifndef INITGUID
#define INITGUID
#include <guiddef.h>
#undef INITGUID
#else
#include <guiddef.h>
#endif
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
#else // !_MIDL_USE_GUIDDEF_
#ifndef __IID_DEFINED__
#define __IID_DEFINED__
typedef struct _IID
{
unsigned long x;
unsigned short s1;
unsigned short s2;
unsigned char c[8];
} IID;
#endif // __IID_DEFINED__
#ifndef CLSID_DEFINED
#define CLSID_DEFINED
typedef IID CLSID;
#endif // CLSID_DEFINED
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
#endif !_MIDL_USE_GUIDDEF_
MIDL_DEFINE_GUID(IID, IID_IClientVirtualDevice,0x40700424,0x0080,0x11d2,0x85,0x1f,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IClientVirtualDeviceSet,0x40700425,0x0080,0x11d2,0x85,0x1f,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IClientVirtualDeviceSet2,0xd0e6eb07,0x7a62,0x11d2,0x85,0x73,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IServerVirtualDevice,0xb5e7a131,0xa7bd,0x11d1,0x84,0xc2,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IServerVirtualDeviceSet,0xb5e7a132,0xa7bd,0x11d1,0x84,0xc2,0x00,0xc0,0x4f,0xc2,0x17,0x59);
MIDL_DEFINE_GUID(IID, IID_IServerVirtualDeviceSet2,0xAECBD0D6,0x24C6,0x11d3,0x85,0xB7,0x00,0xC0,0x4F,0xC2,0x17,0x59);
#undef MIDL_DEFINE_GUID
#ifdef __cplusplus
}
#endif
#endif /* defined(_M_IA64) || defined(_M_AMD64)*/