Technical Article

Warm the cache with a table and its indexes

,

I have had to cache a table that undergoes daily cleanups, but had to go through the leg work of manually building the queries using all columns in all indexes as deletes were taking a long time in an overnight maintenance job.

The physical reads of the cleanup was increasing the duration of blocking.

Proc builds a set of queries for the chosen schema.table, designed to cause index scans with nolocks on Clustered, nonclustered, filtered ,columns store indexes, with no lookups to the table from those indexes to cache the table as quickly as possible without blocking other DML processes.

This should warm the cache with the table.

This proc can either script out the caching queries, or automatically execute the caching queries.

Usage : EXEC     dbo.CacheTable @schemaName = 'HumanResources',@tableName = 'Employee'

-----------------------------------------------------------------
--Author : Doran Mackay
--Usage : EXEC     dbo.CacheTable @schemaName = 'HumanResources',@tableName = 'Employee'
--
--Used to warm the cache of the above table.
--Use case may be to reduce the duration of a cleanup job by precaching the table to reduce the time taken for updates and deletes.
--Another use case will be if you find long running procs have a trend of having physical reads in an OLTP environment.
--
--Works with (NONCLUSTERED and CLUSTERED Row-Stored, CLUSTERED and NONCLUSTERED Column _Store, Filtered) indexes.
--Does not cache HEAPS, Spatial, XML indexes
--I have not made it work with inMemory tables as that would be redundant.
--
--Please let me know of any failures you may encounter.
Create procedure [dbo].[CacheTable] ( @schemaName as sysname, @tableName as sysname )
AS
BEGIN
set nocount on
declare @IndexKeys table (TableName sysname,indexName nvarchar(500) null,IndexKey nvarchar(2000),string nvarchar(max),RowNumber tinyint)

insert into @IndexKeys(TableName ,indexName ,IndexKey,string,RowNumber)
SELECT  QUOTENAME(@schemaName)+'.'+QUOTENAME(@tableName) TableName, i.name indexName,coalesce(IndexKey,'') INDEXKey,
'select sum(checksum(' + IndexKey+ ')/1000000000) from '+ QUOTENAME(@schemaName)+'.'+QUOTENAME(@tableName) + 'with(nolock'
+case WHEN i.name is not null THEN ', index('+QUOTENAME(i.name)+'))' END
+case WHEN i.has_filter =1 THEN ' WHERE '+filter_definition ELSE '' END  as string,
row_number() over(order by i.name) RowNumber
FROM sys.indexes i
INNER JOIN sys.objects o ON i.object_id = o.object_id
INNER JOIN sys.schemas Sch ON Sch.schema_id = o.schema_id
LEFT JOIN (
SELECT object_id, index_id, name, LEFT(subwindow.includeKey, LEN(subwindow.includeKey) - 1) AS 'IndexKey'
FROM( SELECT i.index_id, i.name, object_id,COALESCE(
( SELECT QUOTENAME(c.name) + ',' AS [text()]
  FROMsys.indexes i2
INNER JOIN sys.index_columns ic ON ic.object_id = i2.object_id AND ic.index_id = i2.index_id
INNER JOIN sys.columns c ON c.object_id = ic.object_id ANDc.column_id = ic.column_id
  WHERE 
i.object_id = i2.object_id AND
i.index_id = i2.index_id
and i2.type_desc not in ('XML','HEAP','SPATIAL')
  ORDER BY  i2.name
FOR
  XML PATH('') ),'')  AS includeKey
FROM  sys.indexes i 
) subwindow ) window ON window.object_id = i.object_id AND window.index_id = i.index_id
WHERE   sch.name = @schemaName AND o.name =@tablename and i.type_desc not in ('XML','HEAP','SPATIAL')
   
declare @temp table(columntotal int)
declare @loopMax tinyint = isnull((select max(RowNumber) from @IndexKeys),0),@loopcounter tinyint
if @loopMax=0
Select 'No Indexes to Cache. XML, spatial or Heaps are ignored.'
else
BEGIN --Cache and print each index in list.
declare @execString nvarchar(max)
set @loopcounter = 1
WHILE @loopMax>0 AND @loopcounter<@loopMax+1
BEGIN
set @execString = (select string from @IndexKeys where rownumber = @loopcounter)
print @execString
insert into @temp
exec (@execString)
set @loopcounter = @loopcounter+1
END
END
END
GO

Rate

3 (2)

You rated this post out of 5. Change rating

Share

Share

Rate

3 (2)

You rated this post out of 5. Change rating