Tải bản đầy đủ - 0 (trang)
14-5. Scripting and Executing CREATE Statements for Destination Database Indexes

14-5. Scripting and Executing CREATE Statements for Destination Database Indexes

Tải bản đầy đủ - 0trang

Chapter 14 ■ ETL Process Acceleration



DECLARE @ONLINE BIT = 0

DECLARE @MAX_DEGREE_OF_PARALLELISM TINYINT = 0



-- Create table to hold script elements



IF OBJECT_ID('tempdb..#ScriptElements') IS NOT NULL

DROP TABLE tempdb..#ScriptElements;



CREATE TABLE #ScriptElements (ID INT IDENTITY(1,1), ScriptElement NVARCHAR(MAX))



-- Non-Clustered Indexes



IF OBJECT_ID('tempdb..#Tmp_IndexedFields') IS NOT NULL

DROP TABLE tempdb..#Tmp_IndexedFields;



-- IndexedFields

;

WITH Core_CTE ( INDEX_NAME, Rank, Name )

AS

(

SELECT

INDEX_NAME,ROW_NUMBER()

OVER( PARTITION BY INDEX_NAME ORDER BY INDEX_NAME, key_ordinal)

,CAST(name AS VARCHAR(MAX))

FROM

MetaData_Indexes

WHERE

is_included_column = 0),



Root_CTE ( INDEX_NAME, Rank, Name )

AS ( SELECT INDEX_NAME, Rank, name

FROM Core_CTE

WHERE Rank = 1 ),



Recursion_CTE ( INDEX_NAME, Rank, Name )

AS ( SELECT INDEX_NAME, Rank, name

FROM Root_CTE



UNION ALL



SELECT Core_CTE.INDEX_NAME, Core_CTE.Rank,

Recursion_CTE.name + ', ' + Core_CTE.name

FROM Core_CTE



INNER JOIN Recursion_CTE

ON Core_CTE.INDEX_NAME = Recursion_CTE.INDEX_NAME

AND Core_CTE.Rank = Recursion_CTE.Rank + 1 )



SELECT INDEX_NAME, MAX( Name ) AS IndexFields_Main

INTO #Tmp_IndexedFields

FROM Recursion_CTE

GROUP BY INDEX_NAME;



-- Included fields





821

www.it-ebooks.info



Chapter 14 ■ ETL Process Acceleration



IF OBJECT_ID('tempdb..#Tmp_IncludedFields') IS NOT NULL

DROP TABLE tempdb..#Tmp_IncludedFields;





WITH Core_CTE ( INDEX_NAME, Rank, Name )

AS ( SELECT INDEX_NAME,

ROW_NUMBER() OVER( PARTITION BY INDEX_NAME ORDER BY INDEX_NAME ),

CAST( name AS VARCHAR(MAX) )



FROM MetaData_Indexes WHERE is_included_column = 1 ),



Root_CTE ( INDEX_NAME, Rank, Name )

AS ( SELECT INDEX_NAME, Rank, name

FROM Core_CTE

WHERE Rank = 1 ),



Recursion_CTE ( INDEX_NAME, Rank, Name )

AS ( SELECT INDEX_NAME, Rank, name

FROM Root_CTE



UNION ALL



SELECT Core_CTE.INDEX_NAME, Core_CTE.Rank,

Recursion_CTE.name + ', ' + Core_CTE.name

FROM Core_CTE



INNER JOIN Recursion_CTE

ON Core_CTE.INDEX_NAME = Recursion_CTE.INDEX_NAME

AND Core_CTE.Rank = Recursion_CTE.Rank + 1 )



SELECT

INDEX_NAME, MAX( Name ) AS IndexFields_Included

INTO

#Tmp_IncludedFields

FROM

Recursion_CTE

GROUP BY INDEX_NAME;



-- Create Index Script



-- First, metadata for core indexes



IF OBJECT_ID('tempdb..#Tmp_IndexData') IS NOT NULL

DROP TABLE tempdb..#Tmp_IndexData;



SELECT DISTINCT

MetaData_Indexes.SCHEMA_NAME

,MetaData_Indexes.TABLE_NAME

,MetaData_Indexes.INDEX_NAME

,#Tmp_IndexedFields.IndexFields_Main

,#Tmp_IncludedFields.IndexFields_Included

,MetaData_Indexes.type_desc

,MetaData_Indexes.is_unique

,MetaData_Indexes.has_filter



822

www.it-ebooks.info



Chapter 14 ■ etL proCess aCCeLeration



,MetaData_Indexes.filter_definition

,MetaData_Indexes.is_padded

,MetaData_Indexes.IsNoRecompute

,MetaData_Indexes.[ignore_dup_key]

,MetaData_Indexes.[allow_page_locks]

,MetaData_Indexes.[allow_row_locks]

,MetaData_Indexes.fill_factor

,MetaData_Indexes.DataSpace

,MetaData_Indexes.is_primary_key

,MetaData_Indexes.is_unique_constraint

INTO



#Tmp_IndexData



FROM



MetaData_Indexes

INNER JOIN #Tmp_IndexedFields

ON MetaData_Indexes.INDEX_NAME = #Tmp_IndexedFields.INDEX_NAME

LEFT OUTER JOIN #Tmp_IncludedFields

ON MetaData_Indexes.INDEX_NAME = #Tmp_IncludedFields.INDEX_NAME



-- Create primary keys

INSERT INTO #ScriptElements (ScriptElement)

SELECT DISTINCT

' ALTER TABLE '

+ SCHEMA_NAME + '.' + TABLE_NAME

+ ' ADD CONSTRAINT '

+ INDEX_NAME

+ ' PRIMARY KEY '

+ CASE

WHEN type_desc = 'CLUSTERED' THEN 'CLUSTERED '

ELSE

'NONCLUSTERED '

END

+ ' (' + IndexFields_Main + ')'

+ ' ON [' + DataSpace + ']'

FROM



#Tmp_IndexData



WHERE



#Tmp_IndexData.is_primary_key = 1



-- Create clustered indexes

INSERT INTO



#ScriptElements (ScriptElement)



SELECT DISTINCT

'CREATE '

+ CASE

WHEN is_unique = 1 THEN 'UNIQUE '

ELSE ''

END



823

www.it-ebooks.info



Chapter 14 ■ ETL Process Acceleration



+ 'CLUSTERED INDEX '

+ INDEX_NAME + ' ON ' + SCHEMA_NAME + '.' + TABLE_NAME + ' (' + IndexFields_Main + ')'

+ ' WITH ('

+ CASE

WHEN is_padded = 1 THEN ' PAD_INDEX = OFF, '

ELSE ' PAD_INDEX = ON, '

END

+ CASE

WHEN IsNoRecompute = 1 THEN ' STATISTICS_NORECOMPUTE = OFF, '

ELSE 'STATISTICS_NORECOMPUTE = ON, '

END

+ CASE

WHEN [ignore_dup_key] = 1 THEN ' IGNORE_DUP_KEY = ON, '

ELSE ' IGNORE_DUP_KEY = OFF, '

END

+ CASE

WHEN [allow_page_locks] = 1 THEN ' ALLOW_PAGE_LOCKS = ON, '

ELSE 'ALLOW_PAGE_LOCKS = OFF, '

END

+ CASE

WHEN fill_factor IS NOT NULL THEN ' FILLFACTOR = ' + CAST(fill_factor AS VARCHAR(5)) + ','

ELSE ''

END

+ CASE

WHEN [allow_row_locks] = 1 THEN ' ALLOW_ROW_LOCKS = ON, '

ELSE ' ALLOW_ROW_LOCKS = OFF, '

END

+ CASE

WHEN @SORT_IN_TEMPDB = 1 THEN ' SORT_IN_TEMPDB = ON, '

ELSE ' SORT_IN_TEMPDB = OFF, '

END

+ CASE

WHEN @DROP_EXISTING = 1 THEN ' DROP_EXISTING = ON, '

ELSE ' DROP_EXISTING = OFF, '

END

+ CASE

WHEN @ONLINE = 1 THEN ' ONLINE = ON '

ELSE ' ONLINE = OFF '

END

+ CASE

WHEN @MAX_DEGREE_OF_PARALLELISM = 0 THEN ''

ELSE ' MAXDOP = ' + CAST(@MAX_DEGREE_OF_PARALLELISM AS NVARCHAR(2))

END

+ ')'

+ ' ON [' + DataSpace + ']'

FROM



#Tmp_IndexData



WHERE



#Tmp_IndexData.is_primary_key = 0

AND #Tmp_IndexData.is_unique_constraint = 0

AND type_desc = 'CLUSTERED'



824

www.it-ebooks.info



Chapter 14 ■ ETL Process Acceleration



-- Create Unique Indexes

INSERT INTO #ScriptElements (ScriptElement)

SELECT DISTINCT

' ALTER TABLE '

+ SCHEMA_NAME + '.' + TABLE_NAME

+ ' ADD CONSTRAINT '

+ INDEX_NAME

+ ' UNIQUE '

+ CASE

WHEN type_desc = 'CLUSTERED' THEN 'CLUSTERED '

ELSE

'NONCLUSTERED '

END

+ ' (' + IndexFields_Main + ')'

+ ' ON [' + DataSpace + ']'



FROM

#Tmp_IndexData



WHERE

#Tmp_IndexData.is_unique_constraint = 1 ;



-- Create non-clustered indexes



INSERT INTO #ScriptElements (ScriptElement)



SELECT DISTINCT

'CREATE '

+ CASE

WHEN is_unique = 1 THEN 'UNIQUE '

ELSE ''

END

+ 'NONCLUSTERED INDEX '

+ INDEX_NAME + ' ON ' + SCHEMA_NAME + '.' + TABLE_NAME + ' (' + IndexFields_Main + ')'

+ CASE

WHEN IndexFields_Included IS NOT NULL THEN ' INCLUDE ' + ' (' + IndexFields_Included + ')'

ELSE ''

END

+ CASE

WHEN has_filter = 1 THEN ' WHERE ' + filter_definition

ELSE ''

END

+ ' WITH ('

+ CASE

WHEN is_padded = 1 THEN ' PAD_INDEX = OFF, '

ELSE ' PAD_INDEX = ON, '

END

+ CASE

WHEN IsNoRecompute = 1 THEN ' STATISTICS_NORECOMPUTE = OFF, ' -- CHECK LOGIC

ELSE 'STATISTICS_NORECOMPUTE = ON, '

END



825

www.it-ebooks.info



Chapter 14 ■ ETL Process Acceleration



+ CASE

WHEN [ignore_dup_key] = 1 THEN ' IGNORE_DUP_KEY = ON, '

ELSE ' IGNORE_DUP_KEY = OFF, '

END

+ CASE

WHEN [allow_page_locks] = 1 THEN ' ALLOW_PAGE_LOCKS = ON, '

ELSE 'ALLOW_PAGE_LOCKS = OFF, '

END

+ CASE

WHEN fill_factor IS NOT NULL THEN ' FILLFACTOR = ' + CAST(fill_factor AS VARCHAR(5)) + ','

ELSE ''

END

+ CASE

WHEN [allow_row_locks] = 1 THEN ' ALLOW_ROW_LOCKS = ON, '

ELSE ' ALLOW_ROW_LOCKS = OFF, '

END

+ CASE

WHEN @SORT_IN_TEMPDB = 1 THEN ' SORT_IN_TEMPDB = ON, '

ELSE ' SORT_IN_TEMPDB = OFF, '

END

+ CASE

WHEN @DROP_EXISTING = 1 THEN ' DROP_EXISTING = ON, '

ELSE ' DROP_EXISTING = OFF, '

END

+ CASE

WHEN @ONLINE = 1 THEN ' ONLINE = ON '

ELSE ' ONLINE = OFF '

END

+ CASE

WHEN @MAX_DEGREE_OF_PARALLELISM = 0 THEN ''

ELSE ' MAXDOP = ' + CAST(@MAX_DEGREE_OF_PARALLELISM AS NVARCHAR(2))

END

+ ')'

+ ' ON [' + DataSpace + ']'



FROM

#Tmp_IndexData



WHERE

#Tmp_IndexData.is_primary_key = 0

AND #Tmp_IndexData.is_unique_constraint = 0

AND type_desc = 'NONCLUSTERED'

;

-- Create and execute CREATE scripts



DECLARE @CreateIndex NVARCHAR(MAX)



DECLARE CreateIndex_CUR CURSOR



FOR

SELECT ScriptElement FROM #ScriptElements ORDER BY ID







826

www.it-ebooks.info



Chapter 14 ■ ETL Process Acceleration



OPEN CreateIndex_CUR



FETCH NEXT FROM CreateIndex_CUR INTO @CreateIndex



WHILE @@FETCH_STATUS <> −1

BEGIN



EXEC (@CreateIndex)



FETCH NEXT FROM CreateIndex_CUR INTO @CreateIndex



END ;



CLOSE CreateIndex_CUR ;

DEALLOCATE CreateIndex_CUR ;



How It Works

I realize that this is a very long script, but it is interesting to see how the index metadata can be used to re-create

indexes in a destination database. When re-creating indexes, remember that





If you are dropping all the indexes, drop the nonclustered indexes first, followed by the

clustered index.







If you are creating a clustered index as well as nonclustered indexes, remember to create

the clustered index first.



This script uses the data in the MetaData_Indexes table to re-create all the scripts required to re-create the

indexes as they were before they were dropped. This is not a simple process because complex key columns and

covering indexes have to be managed, and so a judicious use of temporary tables is required.

The script assembles, in this order, the scripts to





Create primary keys.







Create clustered indexes.







Create unique indexes.







Create nonclustered indexes.



All the requisite scripts are stored in the temporary table #ScriptElements. This table is then iterated over

by a cursor that executes the statements—and consequently generates the indexes.



Hints, Tips, and Traps





This script can become part of an ETL process, as described in Recipe 14-2.







You can always change the EXEC to PRINT inside the final cursor loop if you want to script

out the CREATE INDEX statements and store them as text files.







If time is of the essence (and you are using the Enterprise version of SQL Server), you

can create some or all of your indexes offline. This has the advantage of allowing users to

access your finalized data faster, even if some indexes are not immediately available.



827

www.it-ebooks.info



Chapter 14 ■ ETL Process Acceleration



14-6. Storing Metadata, and Then Scripting and Executing

DROP and CREATE Statements for Destination Database

XML Indexes

Problem

You are using XML indexes in a table that will be the destination for a large ETL update and you need to drop and

re-create these indexes as part of the ETL process.



Solution

Store the metadata required to create DROP and CREATE statements for XML indexes. Then use this information to

manage the indexes themselves.

1.



Create the following table to hold the persisted metadata for XML indexes

(C:\SQL2012DIRecipes\CH14\tblMetadata_XMLIndexes.Sql):

IF OBJECT_ID('dbo.Metadata_XMLIndexes') IS NOT NULL

DROP TABLE dbo.Metadata_XMLIndexes;



CREATE TABLE CarSales_Staging.dbo.Metadata_XMLIndexes

(

SERVER_NAME NVARCHAR(128) NULL,

DATABASE_NAME NVARCHAR(128) NULL,

SCHEMA_NAME NVARCHAR(128) NULL,

TABLE_NAME NVARCHAR(128) NULL,

PrimaryIndexName NVARCHAR(128) NULL,

TableID INT NULL,

XMLPrimaryIndexID INT NULL,

XMLSecondaryaryIndexID INT NULL,

INDEX_NAME NVARCHAR(128) NULL,

SecondaryTypeDescription NVARCHAR(60) NULL,

DataSpace NVARCHAR(128) NULL,

Allow_Page_Locks BIT NULL,

Allow_Row_Locks BIT NULL,

Is_Padded BIT NULL,

IsPrimaryXMLIndex BIT NULL,

XMLColumnNameNVARCHAR (128) NULL

) ;

GO



2.



Run the following script to collate and store XML index metadata

(C:\SQL2012DIRecipes\CH14\GatherXMLIndexMetadata.Sql):

INSERT INTO Metadata_XMLIndexes

(

SERVER_NAME

,DATABASE_NAME

,SCHEMA_NAME

,TABLE_NAME



828

www.it-ebooks.info



Chapter 14 ■ ETL Process Acceleration



,PrimaryIndexName

,XMLPrimaryIndexID

,DataSpace

,TableID

,[Allow_Page_Locks]

,[Allow_Row_Locks]

,Is_Padded

,IsPrimaryXMLIndex

,XMLColumnName

)



SELECT

@SERVER_NAME

,@DATABASE_NAME

,SCH.name AS SCHEMA_NAME

,TBL.name AS TABLE_NAME

,XIN.name AS INDEX_NAME

,XIN.index_id AS IndexID

,DSP.name AS DataSpace

,TBL.object_id AS TableID

,XIN.allow_page_locks

,XIN.allow_row_locks

,XIN.is_padded

,1

,COL.name



FROM

sys.tables TBL

INNER JOIN sys.xml_indexes XIN

ON TBL.object_id = XIN.object_id

INNER JOIN sys.schemas SCH

ON TBL.schema_id = SCH.schema_id

INNER JOIN sys.data_spaces DSP

ON XIN.data_space_id = DSP.data_space_id

INNER JOIN sys.index_columns SIC

ON XIN.index_id = SIC.index_id

AND XIN.object_id = SIC.object_id

INNER JOIN sys.columns COL

ON SIC.object_id = COL.object_id

AND SIC.column_id = COL.column_id



WHERE

XIN.secondary_type_desc IS NULL ;



-- Secondary XML indexes



INSERT INTO #Metadata_XMLIndexes

(

SERVER_NAME

,DATABASE_NAME

,SCHEMA_NAME

,TABLE_NAME

,PrimaryIndexName



829

www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

14-5. Scripting and Executing CREATE Statements for Destination Database Indexes

Tải bản đầy đủ ngay(0 tr)

×