-- 表結構
CREATE TABLE xxx_sources (
client_id VARCHAR(255), -- 實際只存數字
channel VARCHAR(255),
KEY idx_client_channel (client_id, channel)
) ENGINE=InnoDB;
-- 慢查詢(11.69s)
SELECT SQL_NO_CACHE channel, COUNT(channel) AS visitors
FROM xxx_sources WHERE client_id = 1301
GROUP BY client_id, channel;
-- EXPLAIN 顯示:type=index, key_len=1032, rows=20,207,319(全索引掃描)
client_id 定義為 VARCHAR(255)(字符類型)。client_id = 1301 使用 數值字面量。ref 訪問,退化為 index 全掃描。-- 快查詢(0.25s)
SELECT SQL_NO_CACHE channel, COUNT(channel) AS visitors
FROM xxx_sources WHERE client_id = '1301'
GROUP BY client_id, channel;
-- EXPLAIN:type=ref, key_len=258, rows=457,184,Using where; Using index
key_len 從 1032 降至 258(VARCHAR(255) 字符集 utf8 → 255×3+2=767?實際 258 為 client_id(255) + channel(1) 部分前綴)。index 變 ref,預估掃描行數從 2000 萬降至 45 萬。ALTER TABLE xxx_sources MODIFY client_id INT UNSIGNED NOT NULL;
-- 索引長度進一步縮減至 4 字節,key_len=4,rows 接近精確匹配行數
| 錯誤模式 | 後果 | 正確做法 |
|---|---|---|
| 數字列定義為 VARCHAR/CHAR | 隱式轉換、索引失效、存儲浪費、排序錯誤('10' < '2') | 用 INT/BIGINT/UNSIGNED |
| 查詢字符列用數值字面量 | 同上 | 加引號 '1301' 或參數綁定 |
| 浮點數列做精確匹配/索引 | 精度陷阱、索引效用低 | 用 DECIMAL 定點數或整數分厘存儲 |
| 通用「萬金油」VARCHAR(255) | 同上 | Schema 設計階段嚴格按業務類型定義 |
結語:「贏在起跑線」—— 數據類型選對,索引才能發揮最大效用。一個 VARCHAR(255) 存數字的設計缺陷,導致生產環境查詢慢 46 倍。Schema Review 時,嚴禁「偷懶型」通用字符串定義,按業務語義嚴格選型,是性能優化的零成本最高收益動作。