MySQL VARCHAR(N) 中的 N 代表字符數而非字節數(4.1+ 版本),LIMIT offset, rows 大偏移量會導致掃描丟棄海量行。本文實測驗證 VARCHAR 語義、LIMIT 不同寫法性能差異(LIMIT 2000,10 vs LIMIT 10),給出書簽分頁、延遲關聯、覆蓋索引優化方案。
CREATE TABLE t (name VARCHAR(5), info CHAR(5)) CHARSET=utf8mb4;
INSERT INTO t VALUES ('abcde', 'abcde'); -- 5 字母
INSERT INTO t VALUES ('你好世界', '你好世界'); -- 4 漢字 + 1 字母 = 5 字符
INSERT INTO t VALUES ('123456', '123456'); -- 6 字符 → 截斷為 '12345'
結果:VARCHAR(5) 存入 5 個字符(字母/漢字/Emoji 均計 1),超出部分截斷(非嚴格模式)或報錯(嚴格模式)。
歷史:MySQL < 4.1 時 N 為字節數;≥ 4.1 統一為字符數。
cnblogs:1 萬行,InnoDB,time 列有索引。SET @@query_cache_type=OFF; SET GLOBAL query_cache_size=0;SET profiling=1;-- A: 大偏移量
SELECT id, time, title FROM cnblogs WHERE time >= 1315646940 ORDER BY time ASC LIMIT 2000, 10;
-- B: 小偏移量
SELECT id, time, title FROM cnblogs WHERE time >= 1315646940 ORDER BY time ASC LIMIT 10;
-- C: 無 WHERE 大偏移量
SELECT id, time, title FROM cnblogs ORDER BY time ASC LIMIT 3000, 10;
LIMIT offset, rows 需掃描並丟棄前 offset 行,耗時隨 offset 線性增長;LIMIT rows 直接取前 N 行,毫秒級。
time/id,下頁 WHERE time > last_time ORDER BY time LIMIT 10,走索引範圍掃描,O(1) 翻頁。SELECT a.* FROM t a JOIN (SELECT id FROM t WHERE ... ORDER BY time LIMIT 2000,10) b ON a.id=b.id,內層只掃描索引列。INDEX (time, id, title) 使內層/外層均走 Index Only Scan。VARCHAR(N) N 為字符數(4.1+),設計列寬按業務字符長度估算,預留 20% 余量。LIMIT offset, rows,改用書簽分頁或延遲關聯。ROW_NUMBER() 可高效實現精確分頁,但仍建議游標分頁。