MySQL 採用行式存儲,磁盤 I/O 以頁為單位。減小單行存儲空間,可提升每頁容納行數,進而降低 I/O 次數、提高緩存命中率。以下從數據類型、索引、字符集、表結構設計等維度系統闡述優化原則。
INDEX(name(20))),提升索引利用率,但無法用於排序。pt-duplicate-key-checker 檢測,如 idx(a,b) 已覆蓋 idx(a) 則刪除後者。| 類型 | 存儲 | 有符號範圍 | 無符號範圍 |
|---|---|---|---|
| TINYINT | 1 字節 | -128 ~ 127 | 0 ~ 255 |
| SMALLINT | 2 字節 | -32768 ~ 32767 | 0 ~ 65535 |
| MEDIUMINT | 3 字節 | -8388608 ~ 8388607 | 0 ~ 16777215 |
| INT | 4 字節 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 |
| BIGINT | 8 字節 | -9223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 |
INT(11) 中的寬度僅影響顯示,不限制存儲範圍;INT(1) 與 INT(20) 存儲完全一致。INT UNSIGNED 存儲,配合 INET_ATON()/INET_NTOA() 轉換,比 CHAR(15) 節省空間且查詢更快。UNSIGNED,擴大正數範圍。CHAR(1) 1 字節 vs VARCHAR(1) 2 字節)。避坑指南:VARCHAR(5) 和 VARCHAR(200) 存 "hello" 佔用空間相同,但後者會導致 MySQL 分配更大固定內存塊用於排序/臨時表,嚴重影響性能。長度定義應精準適度,切勿隨意設大值。
MAX_SORT_LENGTH 前綴,無法用索引排序。ALTER TABLE,不適合頻繁變動的業務枚舉。| 類型 | 存儲 | 範圍 | 時區 | 適用場景 |
|---|---|---|---|---|
| DATETIME | 8 字節 | 1000-01-01 ~ 9999-12-31 | 無關 | 記錄原始創建時間,不隨行更新自動變化 |
| TIMESTAMP | 4 字節 | 1970-01-01 ~ 2038-01-19 | 相關 | 記錄最後修改時間,行更新自動刷新 |
| INT (Unix 時間戳) | 4 字節 | 同 TIMESTAMP | 應用層處理 | 大量時間範圍查詢,索引效率高,BETWEEN 友好 |
結論:範圍查詢多用 INT;創建時間用 DATETIME;修改時間用 TIMESTAMP。
AUTO_INCREMENT、CPU 比較高效。TINYINT 而非 INT,節省 3 字節;主外鍵類型必須精確匹配(含 UNSIGNED),否則隱式轉換導致索引失效與難查的 Bug。INT UNSIGNED + INET_ATON/NTOA 存取,勿用 VARCHAR(15)。DATETIME(3)/TIMESTAMP(3) 毫秒精度;舊版本用 BIGINT 存微秒數。大字段(TEXT/長 VARCHAR)若非高頻訪問,拆到獨立表(一對一關聯)。效果:主表行長大幅縮減 → 每頁容納更多行 → 物理 I/O 驟減、Buffer Pool 命中率飛升。
場景:頻繁 JOIN 多張大表只為取一個小字段。冗餘該字段到主表,雖增大行長、降低頁容納行數,但省去昂貴 JOIN I/O,整體吞吐顯著提升。關鍵:務必保證冗餘字段更新一致性(觸發器/應用層雙寫/消息隊列異步同步)。
TINYINT=1, SMALLINT=2, MEDIUMINT=3, INT=4, BIGINT=8
FLOAT=4 (M<=24) 或 8, DOUBLE=8
DECIMAL: M0? M+2 : M+1)
DATE=3, DATETIME=8, TIMESTAMP=4, TIME=3, YEAR=1
CHAR=M, VARCHAR=M+1
BLOB/TEXT 家族: TINY*=M+1, *=M+2, MEDIUM*=M+3, LONG*=M+4