From d6a5fa111a20eb1c89c57a97605ee78dbe1b1fda Mon Sep 17 00:00:00 2001 From: Jos de Bruijn Date: Fri, 29 Jul 2016 15:16:32 -0700 Subject: [PATCH] moving T-SQL samples scripts for Azure DB from defunct repo --- .gitignore | 13 +- samples/features/in-memory/README.md | 8 +- .../in-memory/t-sql-scripts/README.md | 60 ++ .../clustered_columnstore_sample_queries.sql | 481 +++++++++++ .../sql_in-memory_analytics_sample.sql | 495 +++++++++++ .../sql_in-memory_oltp_sample.sql | 769 ++++++++++++++++++ 6 files changed, 1821 insertions(+), 5 deletions(-) create mode 100644 samples/features/in-memory/t-sql-scripts/README.md create mode 100644 samples/features/in-memory/t-sql-scripts/clustered_columnstore_sample_queries.sql create mode 100644 samples/features/in-memory/t-sql-scripts/sql_in-memory_analytics_sample.sql create mode 100644 samples/features/in-memory/t-sql-scripts/sql_in-memory_oltp_sample.sql diff --git a/.gitignore b/.gitignore index b317c54a..0fd414d9 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,15 @@ samples/databases/wide-world-importers/sample-scripts/always-encrypted/PopulateA *.zip samples/features/in-memory/ticket-reservations/packages/CircularGauge.1.0.0/CreatePackageFile.bat samples/features/in-memory/ticket-reservations/TicketReservations/TicketReservations.dbmdl -samples/databases/wide-world-importers/workload-drivers/vehicle-location-insert/MultithreadedInMemoryTableInsert/obj/Release/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs \ No newline at end of file +samples/databases/wide-world-importers/workload-drivers/vehicle-location-insert/MultithreadedInMemoryTableInsert/obj/Release/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs +samples/databases/wide-world-importers/workload-drivers/vehicle-location-insert/MultithreadedInMemoryTableInsert/obj/Debug/MultithreadedInMemoryTableInsert.csproj.FileListAbsolute.txt +samples/databases/wide-world-importers/sample-scripts/always-encrypted/PopulateAlwaysEncryptedData/obj/Debug/PopulateAlwaysEncryptedData.Properties.Resources.resources +samples/databases/wide-world-importers/sample-scripts/always-encrypted/PopulateAlwaysEncryptedData/obj/Release/PopulateAlwaysEncryptedData.PopulateAlwaysEncryptedDataMain.resources +samples/databases/wide-world-importers/sample-scripts/always-encrypted/PopulateAlwaysEncryptedData/bin/Debug/PopulateAlwaysEncryptedData.vshost.exe.manifest +samples/databases/wide-world-importers/sample-scripts/always-encrypted/PopulateAlwaysEncryptedData/obj/Debug/PopulateAlwaysEncryptedData.PopulateAlwaysEncryptedDataMain.resources +samples/databases/wide-world-importers/workload-drivers/vehicle-location-insert/MultithreadedInMemoryTableInsert/obj/Release/MultithreadedInMemoryTableInsert.Properties.Resources.resources +samples/databases/wide-world-importers/sample-scripts/always-encrypted/PopulateAlwaysEncryptedData/obj/Release/PopulateAlwaysEncryptedData.Properties.Resources.resources +samples/features/in-memory/ticket-reservations/packages/CircularGauge.1.0.0/ReadMe.txt +*.dacpac +samples/features/in-memory/ticket-reservations/TicketReservations/obj/Release/Model.xml +samples/features/in-memory/ticket-reservations/DemoWorkload/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs \ No newline at end of file diff --git a/samples/features/in-memory/README.md b/samples/features/in-memory/README.md index c75ef161..3a51d0fd 100644 --- a/samples/features/in-memory/README.md +++ b/samples/features/in-memory/README.md @@ -6,7 +6,7 @@ In-Memory OLTP can significantly improve OLTP database application performance. - Natively compiled modules execute Transact-SQL statements more efficiently. Read the following resources for more information. -- [In-Memory OLTP (In-Memory Optimization)] (https://msdn.microsoft.com/en-us/library/dn133186.aspx) -- [Quick Start 1: In-Memory OLTP Technologies for Faster Transact-SQL Performance] (https://msdn.microsoft.com/en-us/library/mt694156.aspx) -- [Get started with Columnstore for real time operational analytics] (https://msdn.microsoft.com/en-us/library/dn817827.aspx) -- [Columnstore Indexes Guide] (https://msdn.microsoft.com/en-us/library/gg492088.aspx) +- [In-Memory OLTP (In-Memory Optimization)] (https://msdn.microsoft.com/library/dn133186.aspx) +- [Quick Start 1: In-Memory OLTP Technologies for Faster Transact-SQL Performance] (https://msdn.microsoft.com/library/mt694156.aspx) +- [Get started with Columnstore for real time operational analytics] (https://msdn.microsoft.com/library/dn817827.aspx) +- [Columnstore Indexes Guide] (https://msdn.microsoft.com/library/gg492088.aspx) diff --git a/samples/features/in-memory/t-sql-scripts/README.md b/samples/features/in-memory/t-sql-scripts/README.md new file mode 100644 index 00000000..a677dfb1 --- /dev/null +++ b/samples/features/in-memory/t-sql-scripts/README.md @@ -0,0 +1,60 @@ +# T-SQL scripts supporting SQL In-Memory Features + +Utility scripts, as well as scripts supporting several samples. + + +### Contents + +[About this sample](#about-this-sample)
+[Sample details](#sample-details)
+[Related links](#related-links)
+ + + + +## About this sample + +- **Applies to:** SQL Server 2016 (or higher), Azure SQL Database +- **Key features:** In-Memory OLTP and Columnstore +- **Workload:** OLTP and Analytics +- **Programming Language:** T-SQL +- **Authors:** Jos de Bruijn + + + +## 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 (Premium) +2. SQL Server Management Studio + +## Sample details + +**[enable-in-memory-oltp.sql](enable-in-memory-oltp.sql)** + +Helper script that enables the SQL Server or Azure SQL database for using In-Memory OLTP and configures the recommended database options. + +**[sql_in-memory_oltp_sample.sql](sql_in-memory_oltp_sample.sql)** + +Script to add In-Memory OLTP to the AdventureWorksLT sample database in Azure SQL Database. For details on this sample, see [Install the In-Memory OLTP sample](https://azure.microsoft.com/documentation/articles/sql-database-in-memory/#a-install-the-in-memory-oltp-sample). + +**[sql_in-memory_analytics_sample.sql](sql_in-memory_analytics_sample.sql)** + +Script to add In-Memory Analytics (Columnstore) to the AdventureWorksLT sample database in Azure SQL Database. For details on this sample, see [Install the In-Memory Analytics sample](https://azure.microsoft.com/en-us/documentation/articles/sql-database-in-memory/#b-install-the-in-memory-analytics-sample). + +**[clustered_columnstore_sample_queries.sql](clustered_columnstore_sample_queries.sql)** + +T-SQL queries accompanying the In-Memory Analytics (Columnstore) sample in the AdventureWorksLT sample database for Azure SQL Database. + + + +## Related Links + +For more information, see these articles: +- [In-Memory OLTP (In-Memory Optimization)] (https://msdn.microsoft.com/library/dn133186.aspx) +- [Quick Start 1: In-Memory OLTP Technologies for Faster Transact-SQL Performance] (https://msdn.microsoft.com/library/mt694156.aspx) +- [Get started with Columnstore for real time operational analytics] (https://msdn.microsoft.com/library/dn817827.aspx) +- [Columnstore Indexes Guide] (https://msdn.microsoft.com/library/gg492088.aspx) \ No newline at end of file diff --git a/samples/features/in-memory/t-sql-scripts/clustered_columnstore_sample_queries.sql b/samples/features/in-memory/t-sql-scripts/clustered_columnstore_sample_queries.sql new file mode 100644 index 00000000..89de3b18 --- /dev/null +++ b/samples/features/in-memory/t-sql-scripts/clustered_columnstore_sample_queries.sql @@ -0,0 +1,481 @@ +/************************************************************************* + This sample targets DataWarehouse workload. We recommend using clustered + columnstore index for large tables (million+) rows and traditional rowstore + for tables of size < 1 million rows. The examples here are based on star schema + consisting of FACT and DIMENSION tables.The examples hi-light the both the + storage savings and performance enhancements available in Azure SQL DB + + We have two fact tables FactResellerSalesXL_CCI and FactResellerSalesXL_PageCompressed. + They are identical except one table is based on clustered columnstore index + and other table is regular rowstore table with PAGE compression + + Note: A Pre-requisite is following the instructions in the document: AzureSQLDB_ColumnstoreSetup.docx +************************************************************************* +*/ + + +/************************************************************************************* +STEP 1 - Space comparison between CCI and PAGE compressed table +**********************************************************************************/ +-- How about space? Data space is much smaller. One key point to note is that PAGE compression can +-- compress 2-4x. The difference is less as we have a Primary Key on the table that creates a Unique Non-clustered index +-- The actual data compression savings will depend upon the data and the schema +sp_spaceused 'FactResellerSalesXL_CCI' +GO +sp_spaceused 'FactResellerSalesXL_PageCompressed' +GO + +-- Validate that both tables have the same amount of rows +SELECT count(*) as CCITableCount +FROM FactResellerSalesXL_CCI +GO +SELECT count(*) as PageCompressedTableCount +FROM FactResellerSalesXL_PageCompressed +GO + +-- You can query the following DMV to show that most data in CCI is compressed +SELECT * +FROM sys.dm_db_column_store_row_group_physical_stats +WHERE object_id = object_id('FactResellerSalesXL_CCI') + + + +/********************************************************************* +Step 2 -- Overview +-- Page Compressed BTree table v/s Columnstore table performance differences +-- Enable actual Query Plan in order to see Plan differences when Executing +*/ +-- Ensure Database is in 130 compatibility mode +ALTER DATABASE AdventureworksLT SET compatibility_level = 130 +GO + +-- Execute a typical query that joins the Fact Table with dimension tables +-- Note this query will run on the Page Compressed table, Note down the time +SET STATISTICS IO ON +SET STATISTICS TIME ON +GO + +SELECT c.Year + ,e.ProductCategoryKey + ,FirstName + ' ' + LastName AS FullName + ,count(SalesOrderNumber) AS NumSales + ,sum(SalesAmount) AS TotalSalesAmt + ,Avg(SalesAmount) AS AvgSalesAmt + ,count(DISTINCT SalesOrderNumber) AS NumOrders + ,count(DISTINCT a.CustomerKey) AS CountCustomers +FROM FactResellerSalesXL_PageCompressed a +INNER JOIN DimProduct b ON b.ProductKey = a.ProductKey +INNER JOIN DimCustomer d ON d.CustomerKey = a.CustomerKey +Inner JOIN DimProductSubCategory e on e.ProductSubcategoryKey = b.ProductSubcategoryKey +INNER JOIN DimDate c ON c.DateKey = a.OrderDateKey +WHERE e.ProductCategoryKey =2 + AND c.FullDateAlternateKey BETWEEN '1/1/2014' AND '1/1/2015' +GROUP BY e.ProductCategoryKey,c.Year,d.CustomerKey,d.FirstName,d.LastName +GO +SET STATISTICS IO OFF +SET STATISTICS TIME OFF +GO + + +-- This is the same Prior query on a table with a Clustered Columnstore index CCI +-- The comparison numbers are even more dramatic the larger the table is, this is a 11 million row table only. +SET STATISTICS IO ON +SET STATISTICS TIME ON +GO +SELECT c.Year + ,e.ProductCategoryKey + ,FirstName + ' ' + LastName AS FullName + ,count(SalesOrderNumber) AS NumSales + ,sum(SalesAmount) AS TotalSalesAmt + ,Avg(SalesAmount) AS AvgSalesAmt + ,count(DISTINCT SalesOrderNumber) AS NumOrders + ,count(DISTINCT a.CustomerKey) AS CountCustomers +FROM FactResellerSalesXL_CCI a +INNER JOIN DimProduct b ON b.ProductKey = a.ProductKey +INNER JOIN DimCustomer d ON d.CustomerKey = a.CustomerKey +Inner JOIN DimProductSubCategory e on e.ProductSubcategoryKey = b.ProductSubcategoryKey +INNER JOIN DimDate c ON c.DateKey = a.OrderDateKey +WHERE e.ProductCategoryKey =2 + AND c.FullDateAlternateKey BETWEEN '1/1/2014' AND '1/1/2015' +GROUP BY e.ProductCategoryKey,c.Year,d.CustomerKey,d.FirstName,d.LastName +GO + +SET STATISTICS IO OFF +SET STATISTICS TIME OFF +GO + + + + +/************************************************************************************* +STEP 3 - Constraints +********************************************************************************* +*/ +-- SQL 2014 did not support foreign Key constraints.. +-- Validate there are constraints on this table +SELECT * FROM sys.indexes WHERE object_id = object_id('FactResellerSalesXL_CCI') +SELECT * FROM sys.foreign_keys WHERE parent_object_id = object_id('FactResellerSalesXL_CCI') + +-- Now make change to violate constraint and it should fail. +BEGIN TRAN +DECLARE @SalesOrderNumber NVARCHAR(25) + +SET @SalesOrderNumber = ( + SELECT TOP 1 SalesOrderNumber + FROM FactResellerSalesXL_CCI + ) + +UPDATE FactResellerSalesXL_CCI +SET ProductKey = - 999 +WHERE SalesOrderNumber = @SalesOrderNumber +ROLLBACK + + + +/************************************************************************************* +STEP 4 - Segment Elimination Diagnostics + +-- How about just a normal where clause on the OrderDateKey +-- Can we see Segments eliminated in the stats IO output +-- Look at the messages Tab and you should get what Segments are being eliminated +-- Table 'FactResellerSalesXL_CCI'. Segment reads 2, segment skipped 2. +-- Can I get the same from the Plan? You have to look at the XML Plan + + + ***************************************************************************************** +*/ +SET STATISTICS IO ON +GO +SELECT OrderDateKey FROM FactResellerSalesXL_CCI +WHERE OrderDateKey > 20150901 +GO +SET STATISTICS IO OFF +GO + + +/************************************************************************************* +STEP 5 - Batch Mode improvements under compatibility mode 130 +**********************************************************************************/ +-- Enable Actual QUery Plans for this exercise +-- Hover your mouse over the SORT operator, you will see that the SORT is in batch mode. +-- See the "ACTUAL EXECUTION MODE".. A few operators that were in Row mode in SQL 2014 are now in BATCH mode. + +SET STATISTICS IO ON +SET STATISTICS TIME ON +GO + +SELECT ProductKey + ,count(ProductKey) +FROM FactResellerSalesXL_CCI +GROUP BY ProductKey +ORDER BY ProductKey + +SET STATISTICS IO OFF +SET STATISTICS TIME OFF +GO + + +/***************************************************************************** +-- Batch Mode for serial ( Serial plan aka maxdop 1 in 2014 was in row mode) +-- Again hover over the SCAN node in the query plan and you will see that it is +-- in BATCH mode +***************************************************************************/ +SET STATISTICS IO ON +SET STATISTICS TIME ON +GO + +SELECT ProductKey,sum(TotalProductCost) +FROM FactResellerSalesXL_CCI +GROUP BY ProductKey +OPTION (MAXDOP 1) +GO + + +-- set Database in 120 compatibility mode +ALTER DATABASE AdventureworksLT SET compatibility_level = 120 +GO +-- you will see that this query now runs in rowmode (much slower) +SELECT ProductKey,sum(TotalProductCost) +FROM FactResellerSalesXL_CCI +GROUP BY ProductKey +OPTION (MAXDOP 1) +GO + +-- Ensure Database is back in 130 compatibility mode +ALTER DATABASE AdventureworksLT SET compatibility_level = 130 +GO +SET STATISTICS IO OFF +SET STATISTICS TIME OFF +GO + + + + +/***************************************************************************** + Batch mode for Windows aggregates +******************************************************************************/ +-- you will see that this query runs with in BATCH mode +SELECT ProductKey,OrderDateKey + ,LEAD(OrderQuantity, 1, 0) OVER (ORDER BY OrderDateKey) AS NextQuota +FROM FactResellerSalesXL_CCI +WHERE orderdatekey IN ( 200130301,20130601) + +-- set Database in 120 compatibility mode +ALTER DATABASE AdventureworksLT SET compatibility_level = 120 +GO + +-- you will see that this query now runs in rowmode (much slower) +SELECT ProductKey,OrderDateKey + ,LEAD(OrderQuantity, 1, 0) OVER (ORDER BY OrderDateKey) AS NextQuota +FROM FactResellerSalesXL_CCI +WHERE orderdatekey IN ( 200130301,20130601) +GO + +-- Ensure Database is back in 130 compatibility mode +ALTER DATABASE AdventureworksLT SET compatibility_level = 130 +GO + +-- Multiple distinct batch mode ( was row mode in SQL 2014) +-- In SQL 2014 the hash match would be ROW mode, and all upstream operators would be row mode. +SET STATISTICS IO ON +SET STATISTICS TIME ON +GO + +SELECT [Year],MonthNumberOfYear, + COUNT(DISTINCT rs.ProductKey) AS DistinctProducts + ,COUNT(DISTINCT rs.CustomerKey) AS DistinctCustomers +FROM dbo.FactResellerSalesXL_CCI AS rs +inner join DimDate d on d.DateKey = rs.OrderDateKey +WHERE OrderDateKey between 20130101 and 20140101 +GROUP BY [Year],MonthNumberOfYear +ORDER BY [Year],MonthNumberOfYear; +GO +SET STATISTICS IO OFF +SET STATISTICS TIME OFF +GO + + + + +/************************************************************************************* +STEP 6 - Aggregate Pushdown +**********************************************************************************/ + +SET STATISTICS IO ON +SET STATISTICS TIME ON + +-- Scalar aggregate pushdown without groupby is implemented. +-- Look at the Rows coming out of the SCAN, invariably in the past, 11 million rows would flow out and be filtered to 1 row +SELECT sum(TotalProductCost) +FROM FactResellerSalesXL_CCI + +-- Aggregate Pushdown for a groupby supported as well +SELECT ProductKey + ,count(*) +FROM FactResellerSalesXL_CCI +GROUP BY ProductKey + +SET STATISTICS IO OFF +SET STATISTICS TIME OFF +GO + + + + + +/************************************************************************************* +STEP 7 - String Predicate Pushdown +**********************************************************************************/ +SET STATISTICS IO ON +SET STATISTICS TIME ON +GO + +-- Look at the Query Plan, you will see the Predicate pushed to the SCAN +-- In SQL 2014, this would be a SCAN followed by a Filter +-- Look at the Properties of the SCAN, you will see a Predicate: [AdventureworksDW2014].[dbo].[FactResellerSalesXL_CCI].[CustomerPONumber]=[@1] +SELECT CustomerPONumber +FROM FactResellerSalesXL_CCI +WHERE CustomerPONumber = N'PO35353' + +-- set Database in 120 compatibility mode +ALTER DATABASE AdventureworksLT SET compatibility_level = 120 +GO + +-- you will see that this query now runs in rowmode (much slower) +SELECT CustomerPONumber +FROM FactResellerSalesXL_CCI +WHERE CustomerPONumber = N'PO35353' + +SET STATISTICS IO OFF +SET STATISTICS TIME OFF +GO + +-- Ensure Database is back in 130 compatibility mode +ALTER DATABASE AdventureworksLT SET compatibility_level = 130 +GO + + +/************************************************************************************* +STEP 8 - Non-Clustered Indexes ( btree) on top of Clustered columnstore index +**********************************************************************************/ +-- What abount narrow lookups +-- See missing index for this Plan +-- Also notice no segments were eliminated . There is an optimization where you see a PROBE BITMAP filter pushed to the SCAN + +DBCC DROPCLEANBUFFERS +GO +SET STATISTICS TIME ON +SET STATISTICS IO ON +GO + +SELECT OrderDate + ,SalesAmount +FROM FactResellerSalesXL_CCI a +INNER JOIN DimProduct b ON a.ProductKey = b.ProductKey +WHERE b.EnglishProductName = 'Road-550-W Yellow, 44' +GO + +SET STATISTICS TIME OFF +SET STATISTICS IO OFF +GO + + +/* Now create the missing index */ +CREATE NONCLUSTERED INDEX IndFactResellerSalesXL_CCI_NCI +ON [dbo].[FactResellerSalesXL_CCI] ([ProductKey]) +INCLUDE ([SalesAmount],[OrderDate]) +GO +-- After NCI creation what does the plan look like? +-- Notice the Join has changed from Hash join to a nested loop join +-- Also the inner branch of the nested loop is a seek +-- And IO done is far less and time should be less too in particular CPU time +SET STATISTICS TIME ON +SET STATISTICS IO ON +GO + +SELECT OrderDate + ,SalesAmount +FROM FactResellerSalesXL_CCI a +INNER JOIN DimProduct b ON a.ProductKey = b.ProductKey +WHERE b.EnglishProductName = 'Road-550-W Yellow, 44' +GO + +SET STATISTICS TIME OFF +SET STATISTICS IO OFF +GO + +-- drop the index just created +--Drop index [FactResellerSales_CCI].IndFactResellerSales_CCI_NCI +DROP INDEX IF EXISTS [FactResellerSales_CCI].IndFactResellerSales_CCI_NCI; + +/************************************************************************************* +STEP 9 - Read Committed Snapshot Isolation +**********************************************************************************/ +-- RCSI now supported now, which means you can have CCI on AlwaysOn secondaries +-- Note this may be blocked if you have other connections opened +ALTER DATABASE AdventureworksLT SET READ_COMMITTED_SNAPSHOT ON +GO +ALTER DATABASE AdventureworksLT SET ALLOW_SNAPSHOT_ISOLATION ON +GO + + +-- Now run a Snapshot isolation transaction +SET TRANSACTION ISOLATION LEVEL SNAPSHOT; +GO +BEGIN TRAN +SELECT TOP 10 * FROM FactResellerSalesXL_CCI +COMMIT +GO +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +GO + +-- Revert back if needed +ALTER DATABASE AdventureworksLT SET READ_COMMITTED_SNAPSHOT OFF +GO +ALTER DATABASE AdventureworksLT SET ALLOW_SNAPSHOT_ISOLATION OFF +GO + + + +/************************************************************************************* +STEP 10 - Diagnostics and DMVs +**********************************************************************************/ +-- New DMV +-- See in particular the trim_reason_description which will give you why the rowgroup was closed ( if at all ) before the 1 million mark +-- In this case all of them have 1 million except one, which has the trim_reason_description as REORG +SELECT * FROM sys.dm_db_column_store_row_group_physical_stats + + +-- Do we see NCI metadata? +-- Should appear like any Non clustered index. +SELECT * FROM sys.dm_db_index_operational_stats(NULL, NULL, NULL, NULL) +WHERE database_id = db_id() AND object_id = object_id('FactResellerSalesXL_CCI') + + +-- Metadata for Columnstore indexes +-- This is a new DMV that gives you Usage data like index operational stats for columnstores +-- You can see which rowgroups are scanned how often, locking on rowgroups, latching on row groups +-- Also io_latch waits on rowgroups that indicate Io bottleneck +SELECT * FROM sys.dm_db_column_store_row_group_operational_stats + + +/************************************************************************************* +STEP 11 - Parallel Insert select in compat mode 130 +**********************************************************************************/ +-- Demo parallel Insert from staging table +If object_id('FactResellerSalesXL_CCI_temp') IS NOT NULL +DROP TABLE [FactResellerSalesXL_CCI_temp]; + +-- create ccitest_temp and create a columnstore index +SELECT * INTO FactResellerSalesXL_CCI_temp FROM FactResellerSalesXL_CCI WHERE 1 = 2 +CREATE CLUSTERED columnstore INDEX cci_temp ON FactResellerSalesXL_CCI_temp + + +-- Note this inserts rows in parallel +-- You need the TABLOCK hint +-- Note You may noticed parallelism only in higher sku's than P1. +INSERT INTO FactResellerSalesXL_CCI_temp WITH (TABLOCK) +SELECT TOP 400000 * FROM FactResellerSalesXL_CCI + + +-- check the rowgroups created. +-- you will notice each thread creates its own delta rowgroup. The compressed rowgproup will only be created +-- if number of rows inserted by a thread is > 100k +SELECT * FROM sys.dm_db_column_store_row_group_physical_stats +WHERE object_id = object_id('FactResellerSalesXL_CCI_temp') + + + +/************************************************************************************* +STEP 12 - Supportability - Index REORGANIZE and MERGE +**********************************************************************************/ +-- Force the compression of all rowgroups +ALTER INDEX cci_temp on FactResellerSalesXL_CCI_temp REORGANIZE WITH (COMPRESS_ALL_ROW_GROUPS = ON) + +-- Note that all delta RGs were compressed +-- Also note, that this DMV provides much richer set of information such as why a rowgroup was compressed +SELECT * FROM sys.dm_db_column_store_row_group_physical_stats +WHERE object_id = object_id('FactResellerSalesXL_CCI_temp') + + +-- Now delete a subset of rows +DELETE FactResellerSalesXL_CCI_temp WHERE productkey % 2 = 0 + +-- run the following DMV to note the deleted rows +SELECT * FROM sys.dm_db_column_store_row_group_physical_stats +WHERE object_id = object_id('FactResellerSalesXL_CCI_temp') + + +-- we will now run REORG command to defragement the columnstore index by removing deleted rows +-- This will MERGE smaller rowgroups into larger rowgroups and also reclaim space from the deleted rows +-- http://blogs.msdn.com/b/sqlcat/archive/2015/08/17/sql-2016-columnstore-row-group-merge-policy-and-index-maintenance-improvements.aspx +ALTER INDEX cci_temp on FactResellerSalesXL_CCI_temp REORGANIZE + +-- Validate the new rowgroups that were merged +-- Note only look at the COMPRESSED rowgroup. +SELECT * FROM sys.dm_db_column_store_row_group_physical_stats +WHERE object_id = object_id('FactResellerSalesXL_CCI_temp') + + + + diff --git a/samples/features/in-memory/t-sql-scripts/sql_in-memory_analytics_sample.sql b/samples/features/in-memory/t-sql-scripts/sql_in-memory_analytics_sample.sql new file mode 100644 index 00000000..55fec1f1 --- /dev/null +++ b/samples/features/in-memory/t-sql-scripts/sql_in-memory_analytics_sample.sql @@ -0,0 +1,495 @@ +-- The below script is used to install the sample for In-Memory Analytics in Azure SQL Database. +-- The sample requires a new Premium database, created based on the AdventureWorksLT sample. +-- + +-- Check edition. +/****** Object: Table [dbo].[DimGeography] Script Date: 10/23/2015 1:38:34 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL=130 +GO +If object_id('dbo.DimGeography') is not null + DROP TABLE [dbo].[DimGeography] +GO +CREATE TABLE [dbo].[DimGeography]( + [GeographyKey] [int] IDENTITY(1,1) NOT NULL, + [GeographyAlternateKey] [int] NULL, + [City] [nvarchar](30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [StateProvinceName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [CountryRegionName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [PostalCode] [nvarchar](15) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + CONSTRAINT [PK_DimGeography_GeographyKey] PRIMARY KEY CLUSTERED +( + [GeographyKey] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) +GO +-- Populate Data +insert into DimGeography +select distinct AddressID,City,StateProvince,CountryRegion,PostalCode +from SalesLT.Address + +-- select * from DimGeography + +/****** Object: Table [dbo].[DimCustomer] Script Date: 10/23/2015 1:38:34 PM ******/ +If object_id('dbo.DimCustomer') is not null + DROP TABLE [dbo].[DimCustomer] +GO +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[DimCustomer]( + [CustomerKey] [int] IDENTITY(1,1) NOT NULL, + [GeographyKey] [int] NULL, + [CustomerAlternateKey] [nvarchar](15) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [FirstName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [MiddleName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [LastName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [Suffix] [nvarchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [EmailAddress] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL + CONSTRAINT [PK_DimCustomer_CustomerKey] PRIMARY KEY CLUSTERED +( + [CustomerKey] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) +-- Indexes +/****** Object: Index [IX_DimCustomer_CustomerAlternateKey] Script Date: 10/23/2015 1:38:34 PM ******/ +CREATE NONCLUSTERED INDEX [IX_DimCustomer_CustomerAlternateKey] ON [dbo].[DimCustomer] +( + [CustomerAlternateKey] 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) +GO + +-- Populate Customer Dimension +insert into [DimCustomer] +select GeographyKey,a.CustomerID,a.FirstName,a.MiddleName,a.LastName,a.Suffix,a.EmailAddress +from SalesLT.Customer a +inner join SalesLT.CustomerAddress b on a.CustomerID = b.CustomerID +inner join DimGeography c on c.GeographyAlternateKey = b.AddressID + + +/****** Object: Table [dbo].[DimDate] Script Date: 10/23/2015 1:38:34 PM ******/ +If object_id('dbo.DimDate') is not null + DROP TABLE [dbo].[DimDate] +GO +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[DimDate]( + [DateKey] [int] NOT NULL, + [FullDateAlternateKey] [date] NOT NULL, + [DayNumberOfWeek] [tinyint] NOT NULL, + [EnglishDayNameOfWeek] [nvarchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [DayNumberOfMonth] [tinyint] NOT NULL, + [DayNumberOfYear] [smallint] NOT NULL, + [WeekNumberOfYear] [tinyint] NOT NULL, + [MonthNumberOfYear] [tinyint] NOT NULL, + [EnglishMonthName] [nvarchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [Year] [smallint] NOT NULL + CONSTRAINT [PK_DimDate_DateKey] PRIMARY KEY CLUSTERED +( + [DateKey] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) +GO + +-- Procedure to Populate Date Dimension +If object_id('dbo.spGenerateDateDimension') is not null + DROP PROCEDURE [dbo].[spGenerateDateDimension] +GO +Create Procedure [dbo].[spGenerateDateDimension] +@StartDate Date +, @EndDate Date +AS +;WITH DateList AS ( + SELECT @StartDate AS [DateKey] + UNION ALL + SELECT DATEADD(DAY,1,[DateKey]) + FROM DateList + WHERE DATEADD(DAY,1,[DateKey]) <= @EndDate +) +Insert into DimDate +select + [DateKey]= Cast(CONVERT(VARCHAR,[DateKey],112) as int) --YYYYMMDD + ,[FullDateAlternateKey] = [DateKey] + -- week + ,[DayNumberOfWeek] =DATEPART(WEEKDAY, [DateKey]) + ,[EnglishDayNameOfWeek] = DATENAME(WEEKDAY, [DateKey]) + -- Month + ,[DayNumberOfMonth] = DAY([DateKey]) + --year + ,[DayNumberOfYear] =DATEPART(DAYOFYEAR, [DateKey]) + ,[WeekNumberOfYear] = DATEPART(WEEK, [DateKey]) + -- Year + , [MonthNumberOfYear] = DATEPART(MONTH, [DateKey]) + , [EnglishMonthName] = DATENAME(MONTH, [DateKey]) + + + ,[Year] = YEAR([DateKey]) + --into tbltest + from DateList + OPTION (MAXRECURSION 0) +GO +-- Populate Date Dimension +[spGenerateDateDimension] '1/1/2010', '1/1/2017' +GO + + +/****** Object: Index [AK_DimDate_FullDateAlternateKey] Script Date: 10/23/2015 1:38:34 PM ******/ +CREATE UNIQUE NONCLUSTERED INDEX [AK_DimDate_FullDateAlternateKey] ON [dbo].[DimDate] +( + [FullDateAlternateKey] 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) +GO + +-- select * from DimDate + +/****** Object: Table [dbo].[DimProductCategory] Script Date: 10/23/2015 1:38:34 PM ******/ +If object_id('dbo.DimProductCategory') is not null + DROP TABLE [dbo].[DimProductCategory] +GO +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[DimProductCategory]( + [ProductCategoryKey] [int] IDENTITY(1,1) NOT NULL, + [ProductCategoryAlternateKey] [int] NULL, + [EnglishProductCategoryName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + CONSTRAINT [PK_DimProductCategory_ProductCategoryKey] PRIMARY KEY CLUSTERED +( + [ProductCategoryKey] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON), + CONSTRAINT [AK_DimProductCategory_ProductCategoryAlternateKey] UNIQUE NONCLUSTERED +( + [ProductCategoryAlternateKey] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) +GO + +-- Populate +insert into DimProductCategory +SELECT [ProductCategoryID] ,[Name] FROM [SalesLT].[ProductCategory] +Where ParentProductCategoryID is NULL + + +/****** Object: Table [dbo].[DimProductSubcategory] Script Date: 10/23/2015 1:38:34 PM ******/ +If object_id('dbo.DimProductSubcategory') is not null + DROP TABLE [dbo].[DimProductSubcategory] +GO +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[DimProductSubcategory]( + [ProductSubcategoryKey] [int] IDENTITY(1,1) NOT NULL, + [ProductSubcategoryAlternateKey] [int] NULL, + [EnglishProductSubcategoryName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [ProductCategoryKey] [int] NULL, + CONSTRAINT [PK_DimProductSubcategory_ProductSubcategoryKey] PRIMARY KEY CLUSTERED +( + [ProductSubcategoryKey] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON), + CONSTRAINT [AK_DimProductSubcategory_ProductSubcategoryAlternateKey] UNIQUE NONCLUSTERED +( + [ProductSubcategoryAlternateKey] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) +GO + +-- Populate +insert into DimProductSubcategory +SELECT a.[ProductCategoryID] ,a.[Name],b.[ProductCategoryKey] +FROM [SalesLT].[ProductCategory] a +inner join DimProductCategory b on b.[ProductCategoryAlternateKey] = a.[ParentProductCategoryID] + +-- select * from DimProductSubcategory + + +/****** Object: Table [dbo].[DimProduct] Script Date: 10/23/2015 1:38:34 PM ******/ +If object_id('dbo.DimProduct') is not null + DROP TABLE [dbo].[DimProduct] +GO +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +SET ANSI_PADDING ON +GO +CREATE TABLE [dbo].[DimProduct]( + [ProductKey] [int] IDENTITY(1,1) NOT NULL, + [ProductAlternateKey] [int] NULL, + [ProductSubcategoryKey] [int] NULL, + [EnglishProductName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [ProductNumber] [nvarchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [Color] [nvarchar](15) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [StandardCost] [money] NULL, + [ListPrice] [money] NULL, + [Size] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [Weight] [float] NULL, + [ProductModel] [nvarchar](400) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [StartDate] [datetime] NULL, + [EndDate] [datetime] NULL + CONSTRAINT [PK_DimProduct_ProductKey] PRIMARY KEY CLUSTERED +( + [ProductKey] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON), + CONSTRAINT [AK_DimProduct_ProductAlternateKey_StartDate] UNIQUE NONCLUSTERED +( + [ProductAlternateKey] ASC, + [StartDate] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) + +-- Populate DimProduct +insert into [DimProduct] +SELECT [ProductID],a.ProductCategoryID ,a.[Name],[ProductNumber],[Color],[StandardCost],[ListPrice],[Size],[Weight] + , b.[Name],[SellStartDate],[SellEndDate] +from SalesLT.Product a +inner join SalesLT.ProductModel b on a.ProductModelID = b.ProductModelID +inner join DimProductSubCategory c on c.ProductSubcategoryAlternateKey = a.ProductCategoryID + +-- select * from DimProduct + +-- Fact Table + /****** Object: Table [dbo].[FactResellerSalesXL_CCI] Script Date: 10/23/2015 1:38:34 PM ******/ + IF object_id('dbo.[FactResellerSalesXL_CCI]') is not null + DROP TABLE [dbo].[FactResellerSalesXL_CCI] +GO +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[FactResellerSalesXL_CCI]( + [ProductKey] [int] NOT NULL, + [OrderDateKey] [int] NOT NULL, + [DueDateKey] [int] NOT NULL, + [ShipDateKey] [int] NOT NULL, + [SalesOrderNumber] [nvarchar](20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [SalesOrderLineNumber] [tinyint] NOT NULL, + [RevisionNumber] [tinyint] NULL, + [CustomerKey] [int] NULL, + [OrderQuantity] [smallint] NULL, + [UnitPrice] [money] NULL, + [UnitPriceDiscountPct] [float] NULL, + [DiscountAmount] [float] NULL, + [ProductStandardCost] [money] NULL, + [TotalProductCost] [money] NULL, + [SalesAmount] [money] NULL, + [TaxAmt] [money] NULL, + [LineTotal] numeric(38,6) NULL, + [Freight] [money] NULL, + [CarrierTrackingNumber] [nvarchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [CustomerPONumber] [nvarchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [OrderDate] [smalldatetime] NULL, + [DueDate] [smalldatetime] NULL, + [ShipDate] [smalldatetime] NULL +) +GO + +-- Create a Page Compressed Fact Table for performance comparisons +IF object_id('dbo.[FactResellerSalesXL_PageCompressed]') is not null + DROP TABLE [dbo].[FactResellerSalesXL_PageCompressed] +GO +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[FactResellerSalesXL_PageCompressed]( + [ProductKey] [int] NOT NULL, + [OrderDateKey] [int] NOT NULL, + [DueDateKey] [int] NOT NULL, + [ShipDateKey] [int] NOT NULL, + [SalesOrderNumber] [nvarchar](20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [SalesOrderLineNumber] [tinyint] NOT NULL, + [RevisionNumber] [tinyint] NULL, + [CustomerKey] [int] NULL, + [OrderQuantity] [smallint] NULL, + [UnitPrice] [money] NULL, + [UnitPriceDiscountPct] [float] NULL, + [DiscountAmount] [float] NULL, + [ProductStandardCost] [money] NULL, + [TotalProductCost] [money] NULL, + [SalesAmount] [money] NULL, + [TaxAmt] [money] NULL, + [LineTotal] numeric(38,6) NULL, + [Freight] [money] NULL, + [CarrierTrackingNumber] [nvarchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [CustomerPONumber] [nvarchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [OrderDate] [smalldatetime] NULL, + [DueDate] [smalldatetime] NULL, + [ShipDate] [smalldatetime] NULL +) +GO +ALTER TABLE [dbo].[FactResellerSalesXL_PageCompressed] WITH CHECK ADD + CONSTRAINT [PK_FactResellerSalesXL_PageCompressed_SalesOrderNumber_SalesOrderLineNumber] PRIMARY KEY CLUSTERED + ( + [SalesOrderNumber] ASC, + [SalesOrderLineNumber] ASC + )WITH (PAD_INDEX = OFF, DATA_COMPRESSION = PAGE,STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +Select 'Created Tables.. Please wait Populating Data' as Status +GO + +-- Number of rows distributed by date. +-- This script will take around 15 minutes to populate couple million rows in the fact table. +Select 'Please wait..FactResellerSalesXL_CCI being populated, may take 10-15 mins' as Status +GO +SET NOCOUNT ON +go +if object_id('tempdb..#temp') is not null + drop table #temp +SELECT ABS( DateKey - 20150000 ) % 500 as NumOrdersPerDay,DateKey,FullDateAlternateKey +into #temp +FROM DimDate +where datekey > 20120101 and datekey < 20151026 +order by DateKey asc + +-- Initialization +Declare @SalesOrder int = 5000 +--select sum(ordersperDateKey) from #temp +-- Constant Fields per order +Declare @OrderDateKey int, + @DueDateKey int, + @ShipDateKey int, + @NumOrderLineItems int, -- manufactured. + @OrderDate datetime , + @DueDate datetime , + @ShipDate datetime, + @SalesOrderNumber nvarchar(25), + @NumOrdersPerDateKey int, + @NumSalesLineItems int + +Declare @CustomerPONumber nvarchar(25),@CarrierTrackingNumber nvarchar(25) + +-- Loop through each Date Key to insert that many rows. +DECLARE mycursor CURSOR +FOR SELECT NumOrdersPerDay,DateKey,FullDateAlternateKey from #temp + +OPEN mycursor +FETCH NEXT FROM mycursor +INTO @NumOrdersPerDateKey, @OrderDateKey,@OrderDate + +WHILE @@FETCH_STATUS = 0 +BEGIN + + -- Ship date is 6 days after, due date is 12 days after order for simplicity. + SELECT @ShipDate = dateadd(day,6,@OrderDate), @DueDate= dateadd(day,12,@OrderDate) + SELECT @ShipDateKey = DateKey from DimDate + where FullDateAlternateKey = @ShipDate + SELECT @DueDateKey = DateKey from DimDate + where FullDateAlternateKey = @DueDate + + select @NumOrderLineItems = @NumOrdersPerDateKey %12 + 3 + + +BEGIN TRAN + Declare @OrdersPerDateKey int = 0, @SalesOrderLineNumber int = 1, @i int = 1 + while ( @OrdersPerDateKey < @NumOrdersPerDateKey ) + BEGIN + + select @SalesOrderNumber = N'SO' + cast(@SalesOrder as nvarchar(20)) + ,@CustomerPONumber='PO' + cast(@SalesOrder + 1234 as nvarchar(20)) + ,@CarrierTrackingNumber = Substring(cast(newid() as nvarchar(50)),0,14) + SET @SalesOrder = @SalesOrder + 1 + + ;WITH Ordered AS ( + SELECT ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS RowNumber, + SalesOrderID,OrderQty,ProductID,UnitPrice,UnitPriceDiscount,LineTotal + FROM SalesLT.SalesOrderDetail) + , OrderedDetails AS ( SELECT Rownumber,SalesOrderID,OrderQty,ProductID,UnitPrice,UnitPriceDiscount,LineTotal + FROM Ordered + WHERE RowNumber between @i and @i + @NumOrderLineItems) + insert into FactResellerSalesXL_CCI + select c.ProductKey, @OrderDateKey as OrderDateKey ,@DueDateKey as DueDateKey ,@ShipDateKey as ShipDateKey, @SalesOrderNumber as SalesOrderNumber + ,RowNumber - @i+1 as SalesOrderLineNumber ,b.RevisionNumber,d.CustomerKey + , a.OrderQty as OrderQuantity,a.UnitPrice,a.UnitPriceDiscount as UnitPriceDiscountPct + , DiscountAmount = a.UnitPriceDiscount *c.ListPrice * a.OrderQty + ,c.StandardCost as ProductStandardCost,TotalProductCost = a.OrderQty*c.StandardCost,b.SubTotal as SalesAmount,b.TaxAmt + ,a.LineTotal, b.Freight + ,@CarrierTrackingNumber as CarrierTrackingNumber,@CustomerPONumber as CustomerPONumber + ,@OrderDate as OrderDate,@DueDate as DueDate,@ShipDate as ShipDate + From OrderedDetails a + inner join SalesLT.SalesOrderHeader b on a.SalesOrderID = b.SalesOrderID + inner join DimProduct c on a.ProductID = c.ProductAlternateKey + inner join DimCustomer d on d.CustomerAlternateKey = b.CustomerID + + set @i = @i + @NumOrderLineItems + if @i > 542 + set @i = 1 + + SET @OrdersPerDateKey = @OrdersPerDateKey + 1 + END +COMMIT + +FETCH NEXT FROM mycursor +INTO @NumOrdersPerDateKey, @OrderDateKey,@OrderDate +END + +Close mycursor +deallocate mycursor +GO + +Select 'FactResellerSalesXL_CCI Populated' as Status +GO + +-- Create Index +/****** Object: Index [IndFactResellerSales_CCI] Script Date: 10/23/2015 1:38:34 PM ******/ +CREATE CLUSTERED COLUMNSTORE INDEX [IndFactResellerSales_CCI] ON [dbo].[FactResellerSalesXL_CCI] WITH (MAXDOP = 1) +GO + +-- Create Constraints +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] WITH CHECK ADD + CONSTRAINT [PK_FactResellerSalesXL_CCI_SalesOrderNumber_SalesOrderLineNumber] PRIMARY KEY + ( + [SalesOrderNumber] ASC, + [SalesOrderLineNumber] ASC + )WITH (PAD_INDEX = OFF, DATA_COMPRESSION = PAGE,STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] WITH CHECK ADD CONSTRAINT [FK_FactResellerSalesXL_CCI_DimDate] FOREIGN KEY([OrderDateKey]) +REFERENCES [dbo].[DimDate] ([DateKey]) +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] CHECK CONSTRAINT [FK_FactResellerSalesXL_CCI_DimDate] + +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] WITH CHECK ADD CONSTRAINT [FK_FactResellerSalesXL_CCI_DimDate1] FOREIGN KEY([DueDateKey]) +REFERENCES [dbo].[DimDate] ([DateKey]) +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] CHECK CONSTRAINT [FK_FactResellerSalesXL_CCI_DimDate1] +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] WITH CHECK ADD CONSTRAINT [FK_FactResellerSalesXL_CCI_DimDate2] FOREIGN KEY([ShipDateKey]) +REFERENCES [dbo].[DimDate] ([DateKey]) +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] CHECK CONSTRAINT [FK_FactResellerSalesXL_CCI_DimDate2] + +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] WITH CHECK ADD CONSTRAINT [FK_FactResellerSalesXL_CCI_DimProduct] FOREIGN KEY([ProductKey]) +REFERENCES [dbo].[DimProduct] ([ProductKey]) +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] CHECK CONSTRAINT [FK_FactResellerSalesXL_CCI_DimProduct] +GO + +Select 'FactResellerSalesXL_CCI Clustered Columnstore index created ' as Status +GO + +-- Populate Page Compressed Table +insert into [FactResellerSalesXL_PageCompressed] WITH (TABLOCK) SELECT * from [FactResellerSalesXL_CCI] +GO + +-- Create Constraints on the Page Compressed table +ALTER TABLE [dbo].[FactResellerSalesXL_PageCompressed] WITH CHECK ADD CONSTRAINT [FK_FactResellerSalesXL_PageCompressed_DimDate] FOREIGN KEY([OrderDateKey]) +REFERENCES [dbo].[DimDate] ([DateKey]) +ALTER TABLE [dbo].[FactResellerSalesXL_CCI] CHECK CONSTRAINT [FK_FactResellerSalesXL_CCI_DimDate] + +ALTER TABLE [dbo].[FactResellerSalesXL_PageCompressed] WITH CHECK ADD CONSTRAINT [FK_FactResellerSalesXL_PageCompressed_DimDate1] FOREIGN KEY([DueDateKey]) +REFERENCES [dbo].[DimDate] ([DateKey]) +ALTER TABLE [dbo].[FactResellerSalesXL_PageCompressed] CHECK CONSTRAINT [FK_FactResellerSalesXL_PageCompressed_DimDate1] +ALTER TABLE [dbo].[FactResellerSalesXL_PageCompressed] WITH CHECK ADD CONSTRAINT [FK_FactResellerSalesXL_PageCompressed_DimDate2] FOREIGN KEY([ShipDateKey]) +REFERENCES [dbo].[DimDate] ([DateKey]) +ALTER TABLE [dbo].[FactResellerSalesXL_PageCompressed] CHECK CONSTRAINT [FK_FactResellerSalesXL_PageCompressed_DimDate2] +GO +ALTER TABLE [dbo].[FactResellerSalesXL_PageCompressed] WITH CHECK ADD CONSTRAINT [FK_FactResellerSalesXL_PageCompressed_DimProduct] FOREIGN KEY([ProductKey]) +REFERENCES [dbo].[DimProduct] ([ProductKey]) +ALTER TABLE [dbo].[FactResellerSalesXL_PageCompressed] CHECK CONSTRAINT [FK_FactResellerSalesXL_PageCompressed_DimProduct] +GO + +Select 'FactResellerSalesXL_PageCompressed Populated' as Status +GO \ No newline at end of file diff --git a/samples/features/in-memory/t-sql-scripts/sql_in-memory_oltp_sample.sql b/samples/features/in-memory/t-sql-scripts/sql_in-memory_oltp_sample.sql new file mode 100644 index 00000000..873c5bb5 --- /dev/null +++ b/samples/features/in-memory/t-sql-scripts/sql_in-memory_oltp_sample.sql @@ -0,0 +1,769 @@ +-- The below script is used to install the AdventureWorksLT sample for In-Memory OLTP in Azure SQL Database. +-- The sample requires a new Premium database, created based on the AdventureWorksLT sample. +-- +-- Last updated: 2016-07-29 +-- +-- +-- Copyright (C) Microsoft Corporation. All rights reserved. +-- +-- This source code is intended only as a supplement to Microsoft +-- Development Tools and/or on-line documentation. +-- +-- 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. + + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +SET ANSI_PADDING ON +GO +SET NOCOUNT ON +GO + +/*************************** For memory-optimized tables, automatically map all lower isolation levels (including READ COMMITTED) to SNAPSHOT **********************************/ + +ALTER DATABASE CURRENT SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT = ON +GO +ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 130 +GO + +/*************************** Create Tables **********************************/ + +-- first drop all objects that have a schema-bound dependency on the table + +DROP PROCEDURE IF EXISTS [SalesLT].usp_InsertSalesOrder_inmem +GO +DROP TABLE IF EXISTS [SalesLT].[SalesOrderHeader_inmem] +GO +CREATE TABLE [SalesLT].[SalesOrderHeader_inmem]( + [SalesOrderID] int IDENTITY NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT=100000), + [RevisionNumber] [tinyint] NOT NULL CONSTRAINT [IMDF_SalesOrderHeader_RevisionNumber] DEFAULT ((0)), + [OrderDate] [datetime2] NOT NULL , + [DueDate] [datetime2] NOT NULL, + [ShipDate] [datetime2] NULL, + [Status] [tinyint] NOT NULL CONSTRAINT [IMDF_SalesOrderHeader_Status] DEFAULT ((1)), + [OnlineOrderFlag] bit NOT NULL CONSTRAINT [IMDF_SalesOrderHeader_OnlineOrderFlag] DEFAULT ((1)), + [PurchaseOrderNumber] nvarchar(25) NULL, + [AccountNumber] nvarchar(15) NULL, + [CustomerID] [int] NOT NULL , + [BillToAddressID] [int] NOT NULL, + [ShipToAddressID] [int] NOT NULL, + [CreditCardApprovalCode] [varchar](15) NULL, + [SubTotal] [money] NOT NULL CONSTRAINT [IMDF_SalesOrderHeader_SubTotal] DEFAULT ((0.00)), + [TaxAmt] [money] NOT NULL CONSTRAINT [IMDF_SalesOrderHeader_TaxAmt] DEFAULT ((0.00)), + [Freight] [money] NOT NULL CONSTRAINT [IMDF_SalesOrderHeader_Freight] DEFAULT ((0.00)), + [Comment] [nvarchar](128) NULL, + [ModifiedDate] [datetime2] NOT NULL , + + INDEX IX_CustomerID HASH (CustomerID) WITH (BUCKET_COUNT=10000) +) WITH (MEMORY_OPTIMIZED=ON) +GO + +DROP TABLE IF EXISTS [SalesLT].[SalesOrderDetail_inmem] +GO +CREATE TABLE [SalesLT].[SalesOrderDetail_inmem]( + [SalesOrderID] int NOT NULL INDEX IX_SalesOrderID HASH WITH (BUCKET_COUNT=100000), + [SalesOrderDetailID] bigint IDENTITY NOT NULL, + [OrderQty] [smallint] NOT NULL, + [ProductID] [int] NOT NULL INDEX IX_ProductID HASH WITH (BUCKET_COUNT=100000), + [UnitPrice] [money] NOT NULL, + [UnitPriceDiscount] [money] NOT NULL CONSTRAINT [IMDF_SalesOrderDetail_UnitPriceDiscount] DEFAULT ((0.0)), + [ModifiedDate] [datetime2] NOT NULL , + + CONSTRAINT [imPK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID] PRIMARY KEY NONCLUSTERED HASH + ( [SalesOrderID], + [SalesOrderDetailID] + )WITH (BUCKET_COUNT=1000000) +) WITH (MEMORY_OPTIMIZED=ON) +GO + + +-- type used for TVPs when creating new sales orders +DROP TYPE IF EXISTS [SalesLT].[SalesOrderDetailType_inmem] +GO +CREATE TYPE [SalesLT].[SalesOrderDetailType_inmem] AS TABLE( + [OrderQty] [smallint] NOT NULL, + [ProductID] [int] NOT NULL INDEX IX_ProductID NONCLUSTERED HASH WITH (BUCKET_COUNT=8) +) WITH (MEMORY_OPTIMIZED=ON) +GO + + + +DROP TABLE IF EXISTS [SalesLT].[Product_inmem] +GO +CREATE TABLE [SalesLT].[Product_inmem]( + [ProductID] [int] IDENTITY NOT NULL, + [Name] nvarchar(50) NOT NULL INDEX IX_Name, + [ProductNumber] [nvarchar](25) NOT NULL INDEX IX_ProductNumber, + [Color] [nvarchar](15) NULL, + [StandardCost] [money] NOT NULL, + [ListPrice] [money] NOT NULL, + [Size] [nvarchar](5) NULL, + [Weight] [decimal](8, 2) NULL, + [ProductModelID] [int] NULL, + [SellStartDate] [datetime2] NOT NULL, + [SellEndDate] [datetime2] NULL, + [DiscontinuedDate] [datetime2] NULL, + [ModifiedDate] [datetime2] NOT NULL CONSTRAINT [IMDF_Product_ModifiedDate] DEFAULT (SYSDATETIME()), + + CONSTRAINT [IMPK_Product_ProductID] PRIMARY KEY NONCLUSTERED + ( [ProductID] ) +) WITH (MEMORY_OPTIMIZED=ON) +GO + +DROP TABLE IF EXISTS [SalesLT].[SalesOrderHeader_ondisk] +GO +CREATE TABLE [SalesLT].[SalesOrderHeader_ondisk]( + [SalesOrderID] int IDENTITY NOT NULL PRIMARY KEY, + [RevisionNumber] [tinyint] NOT NULL CONSTRAINT [ODDF_SalesOrderHeader_RevisionNumber] DEFAULT ((0)), + [OrderDate] [datetime2] NOT NULL , + [DueDate] [datetime2] NOT NULL, + [ShipDate] [datetime2] NULL, + [Status] [tinyint] NOT NULL CONSTRAINT [ODDF_SalesOrderHeader_Status] DEFAULT ((1)), + [OnlineOrderFlag] bit NOT NULL CONSTRAINT [ODDF_SalesOrderHeader_OnlineOrderFlag] DEFAULT ((1)), + [PurchaseOrderNumber] nvarchar(25) NULL, + [AccountNumber] nvarchar(15) NULL, + [CustomerID] [int] NOT NULL , + [BillToAddressID] [int] NOT NULL, + [ShipToAddressID] [int] NOT NULL, + [CreditCardApprovalCode] [varchar](15) NULL, + [SubTotal] [money] NOT NULL CONSTRAINT [ODDF_SalesOrderHeader_SubTotal] DEFAULT ((0.00)), + [TaxAmt] [money] NOT NULL CONSTRAINT [ODDF_SalesOrderHeader_TaxAmt] DEFAULT ((0.00)), + [Freight] [money] NOT NULL CONSTRAINT [ODDF_SalesOrderHeader_Freight] DEFAULT ((0.00)), + [Comment] [nvarchar](128) NULL, + [ModifiedDate] [datetime2] NOT NULL , + + INDEX IX_CustomerID (CustomerID) , + INDEX IX_OrderDate (OrderDate ASC) +) +GO + +DROP TABLE IF EXISTS [SalesLT].[SalesOrderDetail_ondisk] +GO +CREATE TABLE [SalesLT].[SalesOrderDetail_ondisk]( + [SalesOrderID] int NOT NULL, + [SalesOrderDetailID] bigint IDENTITY NOT NULL, + [OrderQty] [smallint] NOT NULL, + [ProductID] [int] NOT NULL INDEX IX_ProductID NONCLUSTERED, + [UnitPrice] [money] NOT NULL, + [UnitPriceDiscount] [money] NOT NULL CONSTRAINT [ODDF_SalesOrderDetail_UnitPriceDiscount] DEFAULT ((0.0)), + [ModifiedDate] [datetime2] NOT NULL , + + CONSTRAINT [ODPK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID] PRIMARY KEY + ( [SalesOrderID], [SalesOrderDetailID]) +) +GO + + +DROP PROCEDURE IF EXISTS SalesLT.usp_InsertSalesOrder_ondisk +GO +DROP TYPE IF EXISTS [SalesLT].[SalesOrderDetailType_ondisk] +GO +CREATE TYPE [SalesLT].[SalesOrderDetailType_ondisk] AS TABLE( + [OrderQty] [smallint] NOT NULL, + [ProductID] [int] NOT NULL INDEX IX_ProductID CLUSTERED +) +GO + + + + +DROP TABLE IF EXISTS SalesLT.[Product_ondisk] +GO +CREATE TABLE [SalesLT].[Product_ondisk]( + [ProductID] [int] IDENTITY NOT NULL, + [Name] nvarchar(50) INDEX IX_Name, + [ProductNumber] [nvarchar](25) NOT NULL INDEX IX_ProductNumber, + [Color] [nvarchar](15) NULL, + [StandardCost] [money] NOT NULL, + [ListPrice] [money] NOT NULL, + [Size] [nvarchar](5) NULL, + [Weight] [decimal](8, 2) NULL, + [ProductModelID] [int] NULL, + [SellStartDate] [datetime2] NOT NULL, + [SellEndDate] [datetime2] NULL, + [DiscontinuedDate] [datetime2] NULL, + [ModifiedDate] [datetime2] NOT NULL CONSTRAINT [ODDF_Product_ModifiedDate] DEFAULT (SYSDATETIME()), + CONSTRAINT [ODPK_Product_ProductID] PRIMARY KEY CLUSTERED ([ProductID]) +) +GO + +/*************************** Load data into migrated tables, as well as comparison tables **********************************/ + +SET IDENTITY_INSERT SalesLT.SalesOrderHeader_inmem ON +INSERT INTO SalesLT.SalesOrderHeader_inmem + ([SalesOrderID], + [RevisionNumber], + [OrderDate], + [DueDate], + [ShipDate], + [Status], + [OnlineOrderFlag], + [PurchaseOrderNumber], + [AccountNumber], + [CustomerID], + [BillToAddressID], + [ShipToAddressID], + [CreditCardApprovalCode], + [SubTotal], + [TaxAmt], + [Freight], + [Comment], + [ModifiedDate]) +SELECT + [SalesOrderID], + [RevisionNumber], + [OrderDate], + [DueDate], + [ShipDate], + [Status], + [OnlineOrderFlag], + [PurchaseOrderNumber], + [AccountNumber], + [CustomerID], + [BillToAddressID], + [ShipToAddressID], + [CreditCardApprovalCode], + [SubTotal], + [TaxAmt], + [Freight], + [Comment], + [ModifiedDate] +FROM SalesLT.SalesOrderHeader +SET IDENTITY_INSERT SalesLT.SalesOrderHeader_inmem OFF +GO + +SET IDENTITY_INSERT SalesLT.SalesOrderHeader_ondisk ON +INSERT INTO SalesLT.SalesOrderHeader_ondisk + ([SalesOrderID], + [RevisionNumber], + [OrderDate], + [DueDate], + [ShipDate], + [Status], + [OnlineOrderFlag], + [PurchaseOrderNumber], + [AccountNumber], + [CustomerID], + [BillToAddressID], + [ShipToAddressID], + [CreditCardApprovalCode], + [SubTotal], + [TaxAmt], + [Freight], + [Comment], + [ModifiedDate]) +SELECT * +FROM SalesLT.SalesOrderHeader_inmem WITH (SNAPSHOT) +SET IDENTITY_INSERT SalesLT.SalesOrderHeader_ondisk OFF +GO + +SET IDENTITY_INSERT SalesLT.SalesOrderDetail_inmem ON +INSERT INTO SalesLT.SalesOrderDetail_inmem + ([SalesOrderID], + [SalesOrderDetailID], + [OrderQty], + [ProductID], + [UnitPrice], + [UnitPriceDiscount], + [ModifiedDate]) +SELECT + [SalesOrderID], + [SalesOrderDetailID], + [OrderQty], + [ProductID], + [UnitPrice], + [UnitPriceDiscount], + [ModifiedDate] +FROM SalesLT.SalesOrderDetail +SET IDENTITY_INSERT SalesLT.SalesOrderDetail_inmem OFF +GO + +SET IDENTITY_INSERT SalesLT.SalesOrderDetail_ondisk ON +INSERT INTO SalesLT.SalesOrderDetail_ondisk + ([SalesOrderID], + [SalesOrderDetailID], + [OrderQty], + [ProductID], + [UnitPrice], + [UnitPriceDiscount], + [ModifiedDate]) +SELECT * +FROM SalesLT.SalesOrderDetail_inmem WITH (SNAPSHOT) +SET IDENTITY_INSERT SalesLT.SalesOrderDetail_ondisk OFF +GO + + + + + +SET IDENTITY_INSERT [SalesLT].[Product_inmem] ON +INSERT INTO [SalesLT].[Product_inmem] + ([ProductID], + [Name], + [ProductNumber], + [Color], + [StandardCost], + [ListPrice], + [Size], + [Weight], + [ProductModelID], + [SellStartDate], + [SellEndDate], + [DiscontinuedDate], + [ModifiedDate]) +SELECT + [ProductID], + [Name], + [ProductNumber], + [Color], + [StandardCost], + [ListPrice], + [Size], + [Weight], + [ProductModelID], + [SellStartDate], + [SellEndDate], + [DiscontinuedDate], + [ModifiedDate] +FROM [SalesLT].[Product] +SET IDENTITY_INSERT [SalesLT].[Product_inmem] OFF +GO + +SET IDENTITY_INSERT [SalesLT].[Product_ondisk] ON +INSERT INTO [SalesLT].[Product_ondisk] + ([ProductID], + [Name], + [ProductNumber], + [Color], + [StandardCost], + [ListPrice], + [Size], + [Weight], + [ProductModelID], + [SellStartDate], + [SellEndDate], + [DiscontinuedDate], + [ModifiedDate]) +SELECT * FROM [SalesLT].[Product_inmem] WITH (SNAPSHOT) +SET IDENTITY_INSERT [SalesLT].[Product_ondisk] OFF +GO + + + +/*************************** Update statistics for memory-optimized tables **********************************/ + +UPDATE STATISTICS SalesLT.[SalesOrderHeader_inmem] +WITH FULLSCAN, NORECOMPUTE +GO +UPDATE STATISTICS SalesLT.[SalesOrderDetail_inmem] +WITH FULLSCAN, NORECOMPUTE +GO + + +UPDATE STATISTICS SalesLT.Product_inmem +WITH FULLSCAN, NORECOMPUTE +GO + +/*************************** Create stored procedures **********************************/ + +DROP PROCEDURE IF EXISTS SalesLT.usp_InsertSalesOrder_inmem +GO +CREATE PROCEDURE SalesLT.usp_InsertSalesOrder_inmem + @SalesOrderID int OUTPUT, + @DueDate [datetime2](7) NOT NULL, + @CustomerID [int] NOT NULL, + @BillToAddressID [int] NOT NULL, + @ShipToAddressID [int] NOT NULL, + @SalesOrderDetails SalesLT.SalesOrderDetailType_inmem READONLY, + @Status [tinyint] NOT NULL = 1, + @OnlineOrderFlag [bit] NOT NULL = 1, + @PurchaseOrderNumber [nvarchar](25) = NULL, + @AccountNumber [nvarchar](15) = NULL, + @CreditCardApprovalCode [varchar](15) = NULL, + @Comment nvarchar(128) = NULL +WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER +AS +BEGIN ATOMIC WITH + (TRANSACTION ISOLATION LEVEL = SNAPSHOT, + LANGUAGE = N'us_english') + + DECLARE @OrderDate datetime2 NOT NULL = sysdatetime() + + DECLARE @SubTotal money NOT NULL = 0 + + SELECT @SubTotal = ISNULL(SUM(p.ListPrice),0) + FROM @SalesOrderDetails od + JOIN SalesLT.Product_inmem p on od.ProductID=p.ProductID + + INSERT INTO SalesLT.SalesOrderHeader_inmem + ( DueDate, + Status, + OnlineOrderFlag, + PurchaseOrderNumber, + AccountNumber, + CustomerID, + BillToAddressID, + ShipToAddressID, + CreditCardApprovalCode, + Comment, + OrderDate, + SubTotal, + ModifiedDate) + VALUES + ( + @DueDate, + @Status, + @OnlineOrderFlag, + @PurchaseOrderNumber, + @AccountNumber, + @CustomerID, + @BillToAddressID, + @ShipToAddressID, + @CreditCardApprovalCode, + @Comment, + @OrderDate, + @SubTotal, + @OrderDate + ) + + SET @SalesOrderID = SCOPE_IDENTITY() + + INSERT INTO SalesLT.SalesOrderDetail_inmem + ( + SalesOrderID, + OrderQty, + ProductID, + UnitPrice, + UnitPriceDiscount, + ModifiedDate + ) + SELECT + @SalesOrderID, + od.OrderQty, + od.ProductID, + p.ListPrice, + p.ListPrice, + @OrderDate + FROM @SalesOrderDetails od + JOIN SalesLT.Product_inmem p on od.ProductID=p.ProductID + +END +GO + + + +DROP PROCEDURE IF EXISTS SalesLT.usp_InsertSalesOrder_ondisk +GO +CREATE PROCEDURE SalesLT.usp_InsertSalesOrder_ondisk + @SalesOrderID int OUTPUT, + @DueDate [datetime2](7) , + @CustomerID [int] , + @BillToAddressID [int] , + @ShipToAddressID [int] , + @SalesOrderDetails SalesLT.SalesOrderDetailType_ondisk READONLY, + @Status [tinyint] = 1, + @OnlineOrderFlag [bit] = 1, + @PurchaseOrderNumber [nvarchar](25) = NULL, + @AccountNumber [nvarchar](15) = NULL, + @CreditCardApprovalCode [varchar](15) = NULL, + @Comment nvarchar(128) = NULL +AS +BEGIN + BEGIN TRAN + + DECLARE @OrderDate datetime2 = sysdatetime() + + DECLARE @SubTotal money = 0 + + SELECT @SubTotal = ISNULL(SUM(p.ListPrice),0) + FROM @SalesOrderDetails od + JOIN SalesLT.Product_ondisk p on od.ProductID=p.ProductID + + INSERT INTO SalesLT.SalesOrderHeader_ondisk + ( DueDate, + Status, + OnlineOrderFlag, + PurchaseOrderNumber, + AccountNumber, + CustomerID, + BillToAddressID, + ShipToAddressID, + CreditCardApprovalCode, + Comment, + OrderDate, + SubTotal, + ModifiedDate) + VALUES + ( + @DueDate, + @Status, + @OnlineOrderFlag, + @PurchaseOrderNumber, + @AccountNumber, + @CustomerID, + @BillToAddressID, + @ShipToAddressID, + @CreditCardApprovalCode, + @Comment, + @OrderDate, + @SubTotal, + @OrderDate + ) + + SET @SalesOrderID = SCOPE_IDENTITY() + + INSERT INTO SalesLT.SalesOrderDetail_ondisk + ( + SalesOrderID, + OrderQty, + ProductID, + UnitPrice, + UnitPriceDiscount, + ModifiedDate + ) + SELECT + @SalesOrderID, + od.OrderQty, + od.ProductID, + p.ListPrice, + p.ListPrice, + @OrderDate + FROM @SalesOrderDetails od + JOIN SalesLT.Product_ondisk p on od.ProductID=p.ProductID + + + COMMIT +END +GO + + +/*************************** Demo harness **********************************/ + +DROP PROCEDURE IF EXISTS Demo.usp_DemoInsertSalesOrders +go +DROP PROCEDURE IF EXISTS Demo.usp_DemoInitSeed +GO +DROP TABLE IF EXISTS Demo.DemoSalesOrderDetailSeed +GO +DROP TABLE IF EXISTS Demo.DemoSalesOrderHeaderSeed +GO +DROP PROCEDURE IF EXISTS Demo.usp_DemoReset +GO +DROP SCHEMA IF EXISTS Demo +GO +CREATE SCHEMA Demo +GO + +DROP TABLE IF EXISTS Demo.DemoSalesOrderDetailSeed +GO +CREATE TABLE Demo.DemoSalesOrderDetailSeed +( + [OrderQty] [smallint] NOT NULL, + [ProductID] [int] NOT NULL , + OrderID int NOT NULL INDEX IX_OrderID NONCLUSTERED, + LocalID int IDENTITY NOT NULL PRIMARY KEY NONCLUSTERED +) WITH (MEMORY_OPTIMIZED=ON) +GO + +DROP TABLE IF EXISTS Demo.DemoSalesOrderHeaderSeed +GO +CREATE TABLE Demo.DemoSalesOrderHeaderSeed +( + DueDate [datetime2](7) NOT NULL, + CustomerID [int] NOT NULL, + BillToAddressID [int] NOT NULL, + ShipToAddressID [int] NOT NULL, + LocalID int IDENTITY NOT NULL PRIMARY KEY NONCLUSTERED +) WITH (MEMORY_OPTIMIZED=ON) +GO + +DROP PROCEDURE IF EXISTS Demo.usp_DemoInitSeed +GO +CREATE PROCEDURE Demo.usp_DemoInitSeed @items_per_order int = 5 +AS +BEGIN + DECLARE @ProductID int, + @i int = 1 + DECLARE @seed_order_count int = (SELECT COUNT(*)/@items_per_order FROM SalesLT.Product_inmem) + + DECLARE seed_cursor CURSOR FOR + SELECT + ProductID + FROM SalesLT.Product_inmem WITH (SNAPSHOT) + + OPEN seed_cursor + + FETCH NEXT FROM seed_cursor + INTO @ProductID + + BEGIN TRAN + + DELETE FROM Demo.DemoSalesOrderHeaderSeed WITH (SNAPSHOT) + + INSERT INTO Demo.DemoSalesOrderHeaderSeed + ( + DueDate, + CustomerID, + BillToAddressID, + ShipToAddressID + ) + SELECT + dateadd(d, (rand(BillToAddressID*CustomerID)*10)+1,cast(sysdatetime() as date)), + CustomerID, + BillToAddressID, + ShipToAddressID + FROM SalesLT.SalesOrderHeader_inmem WITH (SNAPSHOT) + + + WHILE @@FETCH_STATUS = 0 + BEGIN + INSERT Demo.DemoSalesOrderDetailSeed + SELECT + @i % 6 + 1, + @ProductID, + @i % (@seed_order_count+1) + + SET @i += 1 + + FETCH NEXT FROM seed_cursor + INTO @ProductID + END + + CLOSE seed_cursor + DEALLOCATE seed_cursor + COMMIT + + UPDATE STATISTICS Demo.DemoSalesOrderDetailSeed + WITH FULLSCAN, NORECOMPUTE + + CHECKPOINT +END +GO + + +DROP PROCEDURE IF EXISTS Demo.usp_DemoReset +GO +CREATE PROCEDURE Demo.usp_DemoReset +AS +BEGIN + truncate table SalesLT.SalesOrderDetail_ondisk + delete from SalesLT.SalesOrderDetail_inmem + truncate table SalesLT.SalesOrderHeader_ondisk + delete from SalesLT.SalesOrderHeader_inmem + + CHECKPOINT + + SET IDENTITY_INSERT SalesLT.SalesOrderHeader_inmem ON + INSERT INTO SalesLT.SalesOrderHeader_inmem + ([SalesOrderID], + [RevisionNumber], + [OrderDate], + [DueDate], + [ShipDate], + [Status], + [OnlineOrderFlag], + [PurchaseOrderNumber], + [AccountNumber], + [CustomerID], + [BillToAddressID], + [ShipToAddressID], + [CreditCardApprovalCode], + [SubTotal], + [TaxAmt], + [Freight], + [Comment], + [ModifiedDate]) + SELECT + [SalesOrderID], + [RevisionNumber], + [OrderDate], + [DueDate], + [ShipDate], + [Status], + [OnlineOrderFlag], + [PurchaseOrderNumber], + [AccountNumber], + [CustomerID], + [BillToAddressID], + [ShipToAddressID], + [CreditCardApprovalCode], + [SubTotal], + [TaxAmt], + [Freight], + [Comment], + [ModifiedDate] + FROM SalesLT.SalesOrderHeader + SET IDENTITY_INSERT SalesLT.SalesOrderHeader_inmem OFF + + + SET IDENTITY_INSERT SalesLT.SalesOrderHeader_ondisk ON + INSERT INTO SalesLT.SalesOrderHeader_ondisk + ([SalesOrderID], + [RevisionNumber], + [OrderDate], + [DueDate], + [ShipDate], + [Status], + [OnlineOrderFlag], + [PurchaseOrderNumber], + [AccountNumber], + [CustomerID], + [BillToAddressID], + [ShipToAddressID], + [CreditCardApprovalCode], + [SubTotal], + [TaxAmt], + [Freight], + [Comment], + [ModifiedDate]) + SELECT * + FROM SalesLT.SalesOrderHeader_inmem WITH (SNAPSHOT) + SET IDENTITY_INSERT SalesLT.SalesOrderHeader_ondisk OFF + + + SET IDENTITY_INSERT SalesLT.SalesOrderDetail_inmem ON + INSERT INTO SalesLT.SalesOrderDetail_inmem + ([SalesOrderID], + [SalesOrderDetailID], + [OrderQty], + [ProductID], + [UnitPrice], + [UnitPriceDiscount], + [ModifiedDate]) + SELECT + [SalesOrderID], + [SalesOrderDetailID], + [OrderQty], + [ProductID], + [UnitPrice], + [UnitPriceDiscount], + [ModifiedDate] + FROM SalesLT.SalesOrderDetail + SET IDENTITY_INSERT SalesLT.SalesOrderDetail_inmem OFF + + + SET IDENTITY_INSERT SalesLT.SalesOrderDetail_ondisk ON + INSERT INTO SalesLT.SalesOrderDetail_ondisk + ([SalesOrderID], + [SalesOrderDetailID], + [OrderQty], + [ProductID], + [UnitPrice], + [UnitPriceDiscount], + [ModifiedDate]) + SELECT * + FROM SalesLT.SalesOrderDetail_inmem WITH (SNAPSHOT) + SET IDENTITY_INSERT SalesLT.SalesOrderDetail_ondisk OFF + + CHECKPOINT +END +GO +/************************************* Initialize Demo seed table ********************************************/ + +EXEC Demo.usp_DemoInitSeed +GO