PlusMagi's Blog By Pitt Phunsanit

SQL Server: ปรับ column string, binary, varchar, nvarchar, char ให้พอดี

ความยากในการออกแบบตาราง column string, binary, varchar, nvarchar ให้พอดีเพราะไม่รู้ว่าหลังจากใช้จริง ๆ แล้ว ได้เผื่อ column size ไว้มากเกินไปรึเปล่า โดยเฉพาะพวกจองพื้นที่ไว้อย่าง char ทำให้เขียน script ไว้ alter column ให้ลดลงเพื่อลดพื้นที่จองไว้ให้ลดลง
alter_table_optimize_by_storage_bytes_columns_types_string_and_binary.sql

/*
================================================================================
STORAGE OPTIMIZATION: FIXED-LENGTH VS VARIABLE-LENGTH
================================================================================
References (Microsoft Learn) :
1. CHAR vs VARCHAR: https://learn.microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver16#storage - CHAR (n) : Spends 'n' bytes regardless of actual data length. - VARCHAR (n) : Spends Actual Length + 2 bytes. 2. NCHAR vs NVARCHAR: https://learn.microsoft.com/en-us/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver16#storage - NCHAR (n) : Spends 'n * 2' bytes regardless of data. - NVARCHAR (n) : Spends (Actual Length * 2) + 2 bytes. 3. BINARY vs VARBINARY: https://learn.microsoft.com/en-us/sql/t-sql/data-types/binary-and-varbinary-transact-sql?view=sql-server-ver16#storage - BINARY (n) : Spends 'n' bytes. - VARBINARY (n) : Spends Actual Length + 2 bytes.
================================================================================
*/ SET NOCOUNT ON; DECLARE @AnalysisTable TABLE (DatabaseName NVARCHAR (128) , -- เพิ่มเพื่อใช้เรียงลำดับ SchemaName NVARCHAR (128) , TableName NVARCHAR (128) , ColumnName NVARCHAR (128) , DataType NVARCHAR (50) , DefinedLength INT, ActualMaxLength INT, RowCountVal INT) ; DECLARE @Db NVARCHAR (128) , @Schema NVARCHAR (128) , @Table NVARCHAR (128) , @Col NVARCHAR (128) , @Type NVARCHAR (50) , @Len INT;
DECLARE @SQL NVARCHAR (MAX) ;
DECLARE @ActualMax INT, @RowCnt INT; -- 1. ดึง Column เป้าหมาย (เพิ่ม table_catalog สำหรับ DB Name) DECLARE cur_all_cols CURSOR FOR
SELECT table_catalog, table_schema, table_name, column_name, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH
FROM information_schema.columns
WHERE DATA_TYPE IN ('char', 'nchar', 'binary', 'varchar', 'nvarchar', 'varbinary') AND CHARACTER_MAXIMUM_LENGTH > 0 AND table_schema NOT IN ('sys', 'information_schema') ; OPEN cur_all_cols;
FETCH NEXT FROM cur_all_cols INTO @Db, @Schema, @Table, @Col, @Type, @Len; -- 2. วนลูป Scan หา Max Length ของจริง
WHILE @@FETCH_STATUS = 0
BEGIN RAISERROR ('Scanning: %s.%s.%s [%s]', 0, 1, @Db, @Schema, @Table, @Col) WITH NOWAIT; IF @Type IN ('char', 'nchar', 'varchar', 'nvarchar') SET @SQL = N'SELECT @MaxVal = MAX (LEN (' + QUOTENAME (@Col) + ')) , @Cnt = COUNT (*) FROM ' + QUOTENAME (@Schema) + '.' + QUOTENAME (@Table) ; ELSE SET @SQL = N'SELECT @MaxVal = MAX (DATALENGTH (' + QUOTENAME (@Col) + ')) , @Cnt = COUNT (*) FROM ' + QUOTENAME (@Schema) + '.' + QUOTENAME (@Table) ; EXEC sp_executesql @SQL, N'@MaxVal INT OUTPUT, @Cnt INT OUTPUT', @MaxVal = @ActualMax OUTPUT, @Cnt = @RowCnt OUTPUT; -- Insert ลงตารางพร้อมชื่อ Database INSERT INTO @AnalysisTable VALUES (@Db, @Schema, @Table, @Col, @Type, @Len, ISNULL (@ActualMax, 0) , @RowCnt) ; FETCH NEXT FROM cur_all_cols INTO @Db, @Schema, @Table, @Col, @Type, @Len;
END CLOSE cur_all_cols;
DEALLOCATE cur_all_cols; -- 3. แสดงผลและสร้าง Script
SELECT DatabaseName, -- แสดงชื่อ DB เป็นคอลัมน์แรก SchemaName, TableName, ColumnName, -- Current State UPPER (DataType) + ' (' + CAST (DefinedLength AS VARCHAR) + ') ' AS CurrentType, ActualMaxLength, -- Target State CASE WHEN DataType IN ('char', 'varchar') THEN 'VARCHAR' WHEN DataType IN ('nchar', 'nvarchar') THEN 'NVARCHAR' WHEN DataType IN ('binary', 'varbinary') THEN 'VARBINARY' END + ' (' + CAST (CASE WHEN ActualMaxLength < 1 THEN 1 ELSE ActualMaxLength END AS VARCHAR) + ') ' AS TargetType, -- Priority CASE WHEN DataType IN ('char', 'nchar', 'binary') AND ActualMaxLength < DefinedLength THEN 'HIGH (Space Saving) ' WHEN DataType IN ('varchar', 'nvarchar', 'varbinary') AND ActualMaxLength < DefinedLength THEN 'LOW (Schema Tightening) ' ELSE 'SKIP' END AS Priority, -- Alter Script 'ALTER TABLE ' + QUOTENAME (SchemaName) + '.' + QUOTENAME (TableName) + ' ALTER COLUMN ' + QUOTENAME (ColumnName) + ' ' + CASE WHEN DataType IN ('char', 'varchar') THEN 'VARCHAR' WHEN DataType IN ('nchar', 'nvarchar') THEN 'NVARCHAR' WHEN DataType IN ('binary', 'varbinary') THEN 'VARBINARY' END + ' (' + CAST (CASE WHEN ActualMaxLength < 1 THEN 1 ELSE ActualMaxLength END AS VARCHAR) + ') ;' AS AlterScript FROM @AnalysisTable
WHERE RowCountVal > 0 AND ActualMaxLength < DefinedLength
ORDER BY Priority, DatabaseName, -- เรียงตาม Database SchemaName, -- เรียงตาม Schema TableName, -- เรียงตาม Table ColumnName; -- เรียงตาม Column

อ่านเพิ่มเติม

Exit mobile version