Oracle 三種字元型別 CHAR、VARCHAR2、VARCHAR 在儲存機制、效能特性、語義細節上有關鍵差異。本文深度對比並給出選型決策樹,助你在建模時做出正確選擇。
| 特性 | CHAR(n) | VARCHAR2(n) | VARCHAR(n) |
|---|---|---|---|
| 長度 | 固定 n 位元組 | 可變,最大 n 位元組 | 同 VARCHAR2(同義詞) |
| 儲存「abc」 | 佔 n 位元組(右側補空格) | 佔 3 位元組 | 同 VARCHAR2 |
| 比較語義 | Blank-padded 比較(補空格後比較) | Non-padded 比較(精確長度比較) | 同 VARCHAR2 |
| 空字串 '' | 儲存為 n 空格 | 儲存為 NULL | 同 VARCHAR2 |
| 效能 | 固定長度,定位快,適合頻繁 UPDATE | 可變長度,需額外 1-2 位元組長度前綴 | 同 VARCHAR2 |
| 行遷移風險 | 無(長度固定) | 高(UPDATE 導致長度變化) | 同 VARCHAR2 |
| 標準相容 | ANSI SQL 標準 | Oracle 專有擴充 | ANSI SQL 標準(但 Oracle 實作同 VARCHAR2) |
CREATE TABLE t (c1 CHAR(5), c2 VARCHAR2(5));
INSERT INTO t VALUES ('abc', 'abc');
SELECT * FROM t WHERE c1 = 'abc '; -- 回傳 1 列(補空格比較)
SELECT * FROM t WHERE c2 = 'abc '; -- 回傳 0 列(精確比較)
CHAR 比較時會將較短值右側補空格至同長度再比較;VARCHAR2 則嚴格比較長度與內容。
INSERT INTO t(c2) VALUES (''); -- 實際儲存 NULL
SELECT * FROM t WHERE c2 IS NULL; -- 回傳該列
Oracle 不支援標準 SQL 的「空字串 ≠ NULL」,這導致 VARCHAR2 無法區分「未輸入」與「輸入空字串」。
當 VARCHAR2 列從短變長(如 'a' → 'abcdefghij'),若區塊剩餘空間不足,Oracle 將列移至新區塊,原位置留下 Forwarding Address,後續存取需雙重 I/O。CHAR 固定長度完全避免此問題。
CHARY/N 旗標、ISO 國別碼、性別、狀態碼、MD5/SHA 雜湊定長。VARCHAR2姓名、地址、說明、JSON/XML 片段、URL。VARCHAR 但實際建表用 VARCHAR2,或在遷移腳本中統一轉換。CLOB 存儲 JSON 含空字串語義。| 操作 | CHAR(10) | VARCHAR2(10) | 差異 |
|---|---|---|---|
| 全表掃描計數 | 1.2 秒 | 1.3 秒 | ~8% 慢(長度前綴解析) |
| 單列點查(索引) | 0.45 ms | 0.48 ms | 可忽略 |
| UPDATE 同長度值 | 0.32 ms | 0.35 ms | 可忽略 |
| UPDATE 變長(觸發行遷移) | N/A | 1.8 ms | CHAR 勝出 |
| 儲存空間(含索引) | 120 MB | 95 MB | VARCHAR2 省 20% |
VARCHAR2,除非明確符合 CHAR 適用場景。VARCHAR2(60)),減少行遷移。CHAR,獲得最佳比較與更新效能。VARCHAR2,避免 VARCHAR 語義誤導。CHAR→CHAR、VARCHAR2→VARCHAR 直接對應。理解 CHAR 的 Blank-padded 語義與 VARCHAR2 的空字串即 NULL 特性,是避免查詢邏輯錯誤、儲存浪費、行遷移效能問題的關鍵。根據「長度固定性、更新頻率、標準相容需求」三維度決策,才能建立既高效又可維護的資料模型。