มีคำถามว่า column นี้ decimal(11, 8) นี้พอมั่ย อันนี้เยอะเกินไปมั๋ย ลองดูใน database ก็ใช้ไม่เหมือนกันเลยแต่ละตาราง เลยลองถามใน gemini ดูมันฉลาดแทนที่จะตอบว่า เลือกใช้ decimal เท่าไหร่ดี มันกลับบอกว่า sql server มันไม่ได้เก็บข้อมูลแบบจำนวน precision กับ scale นะ แต่มันซับซ้อนกว่านั้นโดย ชี้ให้ดู decimal and numeric (Transact-SQL) มันมีตาราง
| Precision | Storage bytes |
|---|---|
| 1 – 9 | 5 |
| 10-19 | 9 |
| 20-28 | 13 |
| 29-38 | 17 |
จะเห็นว่า ถ้าจะเก็บ decimal(11, 8) ใช้ decimal(19, 8) มันเก็บพื้นที่เท่ากันคือ 9 bytes
เลยเขียน query ให้ช่วยตัดสินใจว่าควรใช้ decimal, numeric เป็นเท่าไหร่ตาม Storage bytes
alter_table_optimize_by_storage_bytes_columns_types_numeric.sql
/*
Reference Storage Size:
1. DECIMAL / NUMERIC:
https://learn.microsoft.com/en-us/sql/t-sql/data-types/decimal-and-numeric-transact-sql?view=sql-server-ver16#storage
- Precision 1-9 : 5 bytes
- Precision 10-19 : 9 bytes
- Precision 20-28 : 13 bytes
- Precision 29-38 : 17 bytes
2. FLOAT / REAL:
https://learn.microsoft.com/en-us/sql/t-sql/data-types/float-and-real-transact-sql?view=sql-server-ver16#storage
- REAL (Precision 1-24) : 4 bytes
- FLOAT (Precision 25-53) : 8 bytes
*/
WITH ColumnsToOptimize AS (
SELECT
table_catalog,
table_schema,
table_name,
column_name,
DATA_TYPE,
NUMERIC_PRECISION,
NUMERIC_SCALE,
-- 1. คำนวณ Storage Bytes ที่ใช้อยู่ปัจจุบัน
CASE
-- กลุ่ม DECIMAL / NUMERIC
WHEN DATA_TYPE IN ('decimal', 'numeric') THEN
CASE
WHEN NUMERIC_PRECISION BETWEEN 1 AND 9 THEN 5
WHEN NUMERIC_PRECISION BETWEEN 10 AND 19 THEN 9
WHEN NUMERIC_PRECISION BETWEEN 20 AND 28 THEN 13
WHEN NUMERIC_PRECISION BETWEEN 29 AND 38 THEN 17
END
-- กลุ่ม FLOAT / REAL
WHEN DATA_TYPE IN ('float', 'real') THEN
CASE
WHEN NUMERIC_PRECISION <= 24 THEN 4
WHEN NUMERIC_PRECISION BETWEEN 25 AND 53 THEN 8
END
END AS StorageBytes,
-- 2. คำนวณ Precision สูงสุดที่แนะนำ (ใน Storage Bucket เดียวกัน)
CASE
-- กลุ่ม DECIMAL / NUMERIC
WHEN DATA_TYPE IN ('decimal', 'numeric') THEN
CASE
WHEN NUMERIC_PRECISION BETWEEN 1 AND 9 THEN 9
WHEN NUMERIC_PRECISION BETWEEN 10 AND 19 THEN 19
WHEN NUMERIC_PRECISION BETWEEN 20 AND 28 THEN 28
WHEN NUMERIC_PRECISION BETWEEN 29 AND 38 THEN 38
END
-- กลุ่ม FLOAT / REAL (Step มีแค่ 24 หรือ 53)
WHEN DATA_TYPE IN ('float', 'real') THEN
CASE
WHEN NUMERIC_PRECISION <= 24 THEN 24
WHEN NUMERIC_PRECISION BETWEEN 25 AND 53 THEN 53
END
END AS SuggestedPrecision
FROM
information_schema.columns
WHERE
DATA_TYPE IN ('decimal', 'numeric', 'float', 'real')
AND table_schema NOT IN ('sys', 'information_schema') -- กรอง System Tables ออก
)
SELECT
c.table_catalog AS DatabaseName,
c.table_schema AS SchemaName,
c.table_name AS TableName,
c.column_name AS ColumnName,
-- แสดง Type ปัจจุบัน
CASE
WHEN c.DATA_TYPE IN ('float', 'real') THEN UPPER(c.DATA_TYPE) + '(' + CAST(c.NUMERIC_PRECISION AS VARCHAR) + ')'
ELSE UPPER(c.DATA_TYPE) + '(' + CAST(c.NUMERIC_PRECISION AS VARCHAR) + ', ' + CAST(c.NUMERIC_SCALE AS VARCHAR) + ')'
END AS CurrentType,
-- เหตุผลการ Optimization
'Maximize Precision: Increase ' + CAST(c.NUMERIC_PRECISION AS VARCHAR) +
' -> ' + CAST(c.SuggestedPrecision AS VARCHAR) +
' (Both use ' + CAST(c.StorageBytes AS VARCHAR) + ' bytes)' AS OptimizationReason,
-- สร้าง SuggestedType
CASE
-- Float ใช้พารามิเตอร์ตัวเดียว
WHEN c.DATA_TYPE IN ('float', 'real') THEN
'FLOAT(' + CAST(c.SuggestedPrecision AS VARCHAR(2)) + ')'
-- Decimal ใช้พารามิเตอร์ (p, s)
ELSE
UPPER(c.DATA_TYPE) + '(' + CAST(c.SuggestedPrecision AS VARCHAR(2)) + ', ' + CAST(c.NUMERIC_SCALE AS VARCHAR(2)) + ')'
END AS SuggestedType,
-- สร้างสคริปต์ ALTER
'ALTER TABLE ' + Quotename(c.table_schema) + '.' + Quotename(c.table_name) +
' ALTER COLUMN ' + Quotename(c.column_name) + ' ' +
CASE
WHEN c.DATA_TYPE IN ('float', 'real') THEN
'FLOAT(' + CAST(c.SuggestedPrecision AS VARCHAR(2)) + ')'
ELSE
UPPER(c.DATA_TYPE) + '(' + CAST(c.SuggestedPrecision AS VARCHAR(2)) + ', ' + CAST(c.NUMERIC_SCALE AS VARCHAR(2)) + ')'
END + ';' AS alter_sql
FROM
ColumnsToOptimize AS c
WHERE
-- กรองเอาเฉพาะตัวที่ Precision ไม่เต็ม Bucket
c.SuggestedPrecision IS NOT NULL
AND c.NUMERIC_PRECISION != c.SuggestedPrecision
ORDER BY
DatabaseName, -- เรียงตาม Database
SchemaName, -- เรียงตาม Schema
TableName, -- เรียงตาม Table
ColumnName; -- เรียงตาม Column
อ่านเพิ่มเติม
