直接在 IN (subquery) 中使用 LIMIT 會報錯:
ERROR 1235 (42000): This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
MySQL 禁止在 IN/ALL/ANY/SOME 子查詢中出現 LIMIT。
-- ❌ 報錯
SELECT * FROM mapply
WHERE aid IN (
SELECT aid FROM mapply WHERE state = 1 ORDER BY atime DESC LIMIT 10
);
-- ✅ 正確:子查詢外層套一層 SELECT * FROM ( ... ) AS t
SELECT
i.name, i.phone, i.addr,
c.mname, a.acount, FROM_UNIXTIME(a.atime, '%Y-%m-%d') AS atime
FROM mapply a
RIGHT JOIN infor i ON a.uid = i.uid
INNER JOIN mconfig c ON a.mid = c.mid
WHERE a.aid IN (
SELECT aid FROM (
SELECT aid FROM mapply WHERE state = 1 ORDER BY atime DESC LIMIT 10
) AS tp
);
SELECT aid ... LIMIT 10 先執行,產生最多 10 筆 aid 結果集。SELECT aid FROM ( ... ) AS tp 將其物質化為**衍生表** (臨時表)。IN 子查詢讀取衍生表的 aid,此時**無 LIMIT 限制**,符合語法規則。MySQL 5.6+ 會嘗試將衍生表合併 (Derived Merge),若無法合併則物質化到臨時表,效能尚可接受。
-- 使用 INNER JOIN 直接關聯限制後的結果集
SELECT
i.name, i.phone, i.addr,
c.mname, a.acount, FROM_UNIXTIME(a.atime, '%Y-%m-%d') AS atime
FROM mapply a
RIGHT JOIN infor i ON a.uid = i.uid
INNER JOIN mconfig c ON a.mid = c.mid
INNER JOIN (
SELECT aid FROM mapply WHERE state = 1 ORDER BY atime DESC LIMIT 10
) AS tp ON a.aid = tp.aid;
IN 子查詢的潛在效能問題 (MySQL 早期版本 IN 子查詢優化較差)。tp 的其他欄位 (如排序鍵)。optimizer_switch=derived_merge=on),上述寫法多會被優化為 JOIN,效能極佳。mapply(state, atime) 有**複合索引**支援 WHERE state=1 ORDER BY atime DESC LIMIT 10 避免 filesort。LIMIT 10 等小數值影響微乎其微;若需分頁大偏移 (如 LIMIT 100000, 10) 需改用游標/延遲關聯優化。子查詢 IN + LIMIT → 包一層衍生表 (AS tp) 即可繞過語法限制。實務上優先考慮 JOIN 衍生表 寫法,語義更清晰、優化器友善度更高。