測試環境
- 測試表:
demo_jobs_store,26 萬行,43 個欄位。
- MySQL 版本:5.7+,InnoDB,未建立額外索引(全表掃描)。
實測數據
| 查詢語句 | 掃描行數 | 回傳欄位數 | 執行時間 |
SELECT col1 FROM demo_jobs_store; | 260,000 | 1 | 7.7 秒 |
SELECT col1, col2 FROM demo_jobs_store; | 260,000 | 2 | 15 秒 |
SELECT col1, col2, col3, col4, col5 FROM demo_jobs_store; | 260,000 | 5 | 29 秒 |
SELECT * FROM demo_jobs_store; | 260,000 | 43 | > 30 秒(預估) |
效能差異根因
- 網路傳輸量:欄位越多,結果集體積越大,客戶端接收耗時線性增長。
- Server 端封裝開銷:將行拆解為協議封包,欄位越多 CPU 開銷越大。
- 緩衝區壓力:
net_buffer_length、max_allowed_packet 更易觸發擴容/分片。
- 覆蓋索引機會:指定欄位若恰好命中覆蓋索引,可避免回表,
SELECT * 永遠無法覆蓋索引。
最佳實踐鐵律
- 永遠不要在生產代碼使用
SELECT *。
- 明確列出業務需要的欄位,減少 I/O、網路、CPU 開銷。
- ORM 框架配置:
@EntityGraph、fetch = FetchType.LAZY、Projection 查詢僅需欄位。
- 若確實需要全欄位(如備份、同步),考慮分批、流式處理或專用導出工具。
擴展:EXPLAIN 觀察
EXPLAIN SELECT col1 FROM demo_jobs_store;
-- type=ALL, key=NULL, rows=260000, Extra=Using where
EXPLAIN SELECT * FROM demo_jobs_store;
-- type=ALL, key=NULL, rows=260000, Extra= (無 Using where,但傳輸量大)