首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL VARCHAR 與 LIMIT 易忽略知識點:字符長度語義變更、分頁偏移量性能陷阱與優化

     編輯:MySQL 資料庫相關知識

MySQL VARCHAR(N) 中的 N 代表字符數而非字節數(4.1+ 版本),LIMIT offset, rows 大偏移量會導致掃描丟棄海量行。本文實測驗證 VARCHAR 語義、LIMIT 不同寫法性能差異(LIMIT 2000,10 vs LIMIT 10),給出書簽分頁、延遲關聯、覆蓋索引優化方案。

一、VARCHAR(N):N 是字符數,非字節數

實測驗證(MySQL 5.6, utf8mb4)

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 統一為字符數。

二、LIMIT 大偏移量性能陷阱

測試環境

  • 表 cnblogs:1 萬行,InnoDB,time 列有索引。
  • 關閉查詢緩存:SET @@query_cache_type=OFF; SET GLOBAL query_cache_size=0;
  • 開啟 Profile:SET profiling=1;

三條 SQL 對比

-- 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 行,毫秒級。

三、優化方案:避免大偏移量

  1. 書簽分頁(游標分頁):記住上一頁最大 time/id,下頁 WHERE time > last_time ORDER BY time LIMIT 10,走索引範圍掃描,O(1) 翻頁。
  2. 延遲關聯:SELECT a.* FROM t a JOIN (SELECT id FROM t WHERE ... ORDER BY time LIMIT 2000,10) b ON a.id=b.id,內層只掃描索引列。
  3. 覆蓋索引:INDEX (time, id, title) 使內層/外層均走 Index Only Scan。
  4. 應用層緩存:熱門分頁結果寫 Redis,減少 DB 壓力。

四、總結

  • VARCHAR(N) N 為字符數(4.1+),設計列寬按業務字符長度估算,預留 20% 余量。
  • 永遠不要在生產環境使用大偏移量 LIMIT offset, rows,改用書簽分頁或延遲關聯。
  • MySQL 8.0+ 窗口函數 ROW_NUMBER() 可高效實現精確分頁,但仍建議游標分頁。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved