This query works as intended, but it's just really slow. Does anyone here have recommendations to improve performance?
I essentially just creating a temp table to store all the table and column names, and cycling through them via a WHILE statement, to create dynamic inserts into another table with the details I want.
My latest run took about 21 minutes, which isn't entirely terrible (considering the task), but I'd love to get some input on how/where it can be fine tuned.
USE <DATABASE>;
IF NOT EXISTS(SELECT *
FROM sys.schemas WHERE name='temp')
BEGIN
EXEC ('CREATE SCHEMA temp');
END;
IF OBJECT_ID('temp.columns') IS NOT NULL
BEGIN
DROP TABLE temp.columns
END;
SELECT [table_name]
, [column_name]
, [data_type]
, [is_nullable]
, [numeric_scale]
, [ordinal_position]
INTO [temp].[columns]
FROM information_schema.columns c
WHERE table_schema = 'dbo'
-- AND table_name = 'CONTACTS'
;
IF OBJECT_ID('_TableColumnsUsed') IS NOT NULL
BEGIN
DROP TABLE _TableColumnsUsed
END;
CREATE TABLE _TableColumnsUsed (Table_Name VARCHAR(255) NULL, Column_Position INT, Column_Name VARCHAR(255) NULL, Min_Value VARCHAR(MAX) NULL, Max_Value VARCHAR(MAX) NULL);
DECLARE
@CurrentTable VARCHAR(255)
, @CurrentColumn VARCHAR(255)
, @CurrentIsNullable VARCHAR(3)
, @CurrentNumeric BIT
, @CurrentPosition INT
, @SQL VARCHAR(MAX);
WHILE
(
SELECT COUNT(1)
FROM temp.columns
) > 0
BEGIN
SELECT TOP 1 @CurrentTable = [Table_Name]
, @CurrentColumn = [Column_Name]
, @CurrentIsNullable = [is_nullable]
, @CurrentNumeric = IIF([numeric_scale] IS NULL, 0, 1)
, @CurrentPosition = [ordinal_position]
FROM temp.columns c
WHERE [table_name] NOT IN ('_TableColumnsUsed')
ORDER BY [table_name]
, [ordinal_position];
SET @SQL = 'INSERT INTO _TableColumnsUsed (Table_Name, Column_Position, Column_Name, Min_Value, Max_Value)
SELECT Table_Name = '''+@CurrentTable+'''
, Column_Position = '+CAST(@CurrentPosition AS VARCHAR(3))+'
, Column_Name = '''+@CurrentColumn+'''
, Min_Value = MIN(CAST('+@CurrentColumn+' AS VARCHAR(MAX)))
, Max_Value = MAX(CAST('+@CurrentColumn+' AS VARCHAR(MAX)))
FROM '+@CurrentTable+'
WHERE '+IIF(@CurrentIsNullable = 'NO', '1=1',
CASE
WHEN @CurrentNumeric = 0
THEN 'ISNULL(CAST('+@CurrentColumn+' AS VARCHAR(MAX)),'''') <> '''''
WHEN @CurrentNumeric = 1
THEN 'ISNULL('+@CurrentColumn+',0.00) <> 0.00'
ELSE '1=1'
END);
EXEC (@SQL);
DELETE c
FROM [temp].[columns] [c]
WHERE [c].[table_name] = @CurrentTable
AND [c].[column_name] = @CurrentColumn;
END;
/* -- Dynamic SQL Output Example
SELECT Table_Name = 'CONTACTS'
, Column_Position = 17
, Column_Name = 'ZIP'
, Min_Value = MIN(CAST(ZIP AS VARCHAR(MAX)))
, Max_Value = MAX(CAST(ZIP AS VARCHAR(MAX)))
FROM CONTACTS
WHERE 1=1
*/
SELECT Table_Name, Column_Position, Column_Name, Min_Value, Max_Value
FROM _TableColumnsUsed;
Try this, it should work in seconds:
The statement creates an all-in-one
UNION ALL
query which is executed viaEXEC
You can uncomment the
PRINT
to see the executed statement.Can't say that it will run any faster, depends on the size of your database but here's a modded version of a profiling script I created that should meet your needs.