很多開發者期望「表數據物理順序按業務排序」,嘗試 ALTER TABLE t ORDER BY col1, col2 卻報錯 Error 1105: ORDER BY ignored as there is a user-defined clustered index。本文從關係論、InnoDB 聚簇索引架構、MyISAM 歷史差異、主鍵設計原則四個維度,徹底講清「表無序論」、排序的正確姿勢與主鍵選型鐵律。
CREATE TABLE `tableMain` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `value1` VARCHAR(45) NOT NULL, `value2` VARCHAR(50) NOT NULL, `value3` INT NOT NULL, `value4` TIMESTAMP NOT NULL, `value5` INT NOT NULL, PRIMARY KEY (`id`) ); ALTER TABLE tableMain ORDER BY value2 ASC, value3 ASC, value4 ASC; -- ERROR 1105 (HY000): ORDER BY ignored as there is a user-defined clustered index in the table 'tableMain' -- If you want rows in a particular sequence, specify an appropriate ORDER BY clause in your query.
ALTER TABLE t ORDER BY col 會重寫數據文件按指定列排序-- 1. 查詢時顯式排序(唯一保證順序的方式) SELECT * FROM tableMain ORDER BY value2 ASC, value3 ASC, value4 ASC; -- 2. 為排序列建立複合索引(避免 filesort) CREATE INDEX idx_tableMain_sort ON tableMain (value2, value3, value4); -- 3. EXPLAIN 驗證:Extra 不含 Using filesort 即成功 EXPLAIN SELECT * FROM tableMain ORDER BY value2, value3, value4;
-- 方案:將業務排序列提升為主鍵前導列 CREATE TABLE `tableMain` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `value1` VARCHAR(45) NOT NULL, `value2` VARCHAR(50) NOT NULL, `value3` INT NOT NULL, `value4` TIMESTAMP NOT NULL, `value5` INT NOT NULL, PRIMARY KEY (`value2`, `value3`, `value4`, `id`), -- 聚簇索引即業務順序 UNIQUE KEY `ux_id` (`id`) -- 保證 id 唯一 );
代價**:
結論**:極不推薦,除非極端只讀、單表、無二級索引、無外鍵場景。
INDEX idx_biz_sort (value2, value3, value4)INDEX idx_cover (value2, value3, value4, value1, value5) 實現 Using indexLIMIT 1000000, 20 改為 WHERE value2 > 'last_val' ORDER BY value2 LIMIT 20(游標分頁)大概率他們的表引擎是 MyISAM(或未顯式指定 ENGINE=InnoDB 的舊版本預設)。MyISAM 支援 ALTER TABLE ORDER BY,但不代表這是正確設計。InnoDB 是現代 MySQL 默認且唯一推薦的事務引擎,架構決定了物理順序不可變。
核心心法**:表無序,序在查;索引支撐,序在鍵;主鍵無業務,業務建二級。 拋棄「物理順序」執著,擁抱「邏輯排序 + 索引加速」的工程現實。