forked from DavidSchanzer/Sql-Server-DBA-Toolbox
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspa_ShrinkColumnSizes.sql
149 lines (127 loc) · 4.89 KB
/
spa_ShrinkColumnSizes.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
-- spa_ShrinkColumnSizes
-- Part of the SQL Server DBA Toolbox at https://github.com/DavidSchanzer/Sql-Server-DBA-Toolbox
-- This script create a stored procedure that queries the data in VARCHAR and INT columns to see if they can be reduced in size:
-- VARCHAR to CHAR if the min(length) = max(length), else VARCHAR(max(length)), and INT to SMALLINT or TINYINT.
-- The output is a series of ALTER TABLE ALTER COLUMN statements.
CREATE OR ALTER PROC dbo.spa_ShrinkColumnSizes
(
@SchemaName NVARCHAR(40),
@TableName NVARCHAR(40),
@PrintOnly BIT = 1,
@Debug BIT = 0
)
AS
BEGIN
DECLARE @Table VARCHAR(100) = @SchemaName + N'.' + @TableName;
DECLARE @ColumnName NVARCHAR(50),
@ColumnID TINYINT,
@ColumnType NVARCHAR(10),
@ColumnLength SMALLINT,
@SQLStatus SMALLINT,
@MinColumnLen SMALLINT,
@MaxColumnLen SMALLINT,
@SQL NVARCHAR(500),
@ParmDefinition NVARCHAR(100),
@NewColumnType NVARCHAR(10),
@NewColumnDef NVARCHAR(20),
@Count INT,
@Nullity VARCHAR(10),
@MinVal INT,
@MaxVal INT;
IF @Debug = 1
SELECT '@Table = ' + @Table;
DECLARE ColumnCur CURSOR LOCAL FAST_FORWARD FOR
SELECT c.name AS ColumnName,
c.column_id AS ColumnID,
t.name AS ColumnType,
c.max_length AS ColumnLength
FROM sys.columns AS c
INNER JOIN sys.types AS t
ON t.system_type_id = c.system_type_id
WHERE c.object_id = OBJECT_ID(@Table)
AND t.name IN ( N'varchar', N'int' );
OPEN ColumnCur;
IF @@ERROR <> 0
BEGIN
RETURN -1;
END;
FETCH ColumnCur
INTO @ColumnName,
@ColumnID,
@ColumnType,
@ColumnLength;
SET @SQLStatus = @@FETCH_STATUS;
WHILE @SQLStatus = 0
BEGIN
IF @Debug = 1
SELECT '@ColumnName = ' + @ColumnName + ', @ColumnID = ' + CAST(@ColumnID AS VARCHAR) + ', @ColumnType = '
+ @ColumnType + ', @ColumnLength = ' + CAST(@ColumnLength AS VARCHAR);
IF @ColumnType = 'varchar'
BEGIN
SET @SQL
= N'SELECT @MinColumnLen = MIN(LEN(' + @ColumnName + N')), @MaxColumnLen = MAX(LEN(' + @ColumnName
+ N')) FROM ' + @Table;
SET @ParmDefinition = N'@MinColumnLen SMALLINT OUTPUT, @MaxColumnLen SMALLINT OUTPUT';
EXEC sp_executesql @stmt = @SQL,
@params = @ParmDefinition,
@MinColumnLen = @MinColumnLen OUTPUT,
@MaxColumnLen = @MaxColumnLen OUTPUT;
IF @MinColumnLen = @MaxColumnLen
SET @NewColumnType = N'CHAR';
ELSE
SET @NewColumnType = N'VARCHAR';
SET @NewColumnDef = @NewColumnType + N'(' + CAST(@MaxColumnLen AS VARCHAR(10)) + N')';
END;
ELSE -- int
BEGIN
SET @SQL
= N'SELECT @MinVal = MIN(' + @ColumnName + N'), @MaxVal = MAX(' + @ColumnName + N') FROM ' + @Table;
SET @ParmDefinition = N'@MinVal INT OUTPUT, @MaxVal INT OUTPUT';
EXEC sp_executesql @stmt = @SQL,
@params = @ParmDefinition,
@MinVal = @MinVal OUTPUT,
@MaxVal = @MaxVal OUTPUT;
IF @MinVal >= 0
AND @MinVal <= 255
AND @MaxVal > 0
AND @MaxVal <= 255
SET @NewColumnType = N'TINYINT';
ELSE IF @MinVal >= -32768
AND @MinVal <= 32767
AND @MaxVal > -32768
AND @MaxVal <= 32767
SET @NewColumnType = N'SMALLINT';
ELSE
SET @NewColumnType = N'INT';
SET @NewColumnDef = @NewColumnType;
END;
SET @SQL = N'SELECT @Count = COUNT(1) FROM ' + @Table + N' WHERE ' + @ColumnName + N' IS NULL';
SET @ParmDefinition = N'@Count INT OUTPUT';
EXEC sp_executesql @stmt = @SQL,
@params = @ParmDefinition,
@Count = @Count OUTPUT;
IF @Count > 0
SET @Nullity = N'NULL';
ELSE
SET @Nullity = N'NOT NULL';
SET @SQL = N'ALTER TABLE ' + @Table + N' ALTER COLUMN ' + @ColumnName + N' ' + @NewColumnDef + N' ' + @Nullity;
PRINT @SQL;
IF @PrintOnly = 0
EXEC (@SQL);
FETCH ColumnCur
INTO @ColumnName,
@ColumnID,
@ColumnType,
@ColumnLength;
SET @SQLStatus = @@FETCH_STATUS;
END;
CLOSE ColumnCur;
DEALLOCATE ColumnCur;
END;
GO
-- Example
EXEC dbo.spa_ShrinkColumnSizes @SchemaName = N'<SchemaName>',
@TableName = N'<TableName>',
@PrintOnly = 1,
@Debug = 0;
GO