爲什麼要學查詢優化?
想象一下,當你寫了一條SQL查詢,點擊執行後卻要等十幾秒頁面才加載出來——這時候用戶可能已經放棄了。查詢優化的核心目標就是讓SQL更快執行,減少數據庫負載,提升整個系統的響應速度。對初學者來說,掌握一些基礎技巧,就能顯著改善查詢效率,避免“簡單問題複雜化”。
一、新手最容易犯的3個查詢錯誤¶
在優化之前,先看看你是否踩過這些坑:
1. 全表掃描:沒加索引,讓數據庫從頭遍歷整個表(比如查詢SELECT * FROM users WHERE name='小明',而name是大表的字段且無索引)。
2. SELECT :一次性取所有字段,導致大量不必要的數據傳輸和內存佔用。
3. 濫用JOIN或複雜條件*:JOIN太多表、或在WHERE裏用函數包裹索引字段(比如YEAR(create_time)=2023)。
二、5個必學的簡單優化技巧¶
技巧1:給查詢條件加索引(避免全表掃描)¶
問題:如果查詢條件字段沒有索引,數據庫會“逐個檢查”表中每一行,這就是“全表掃描”,數據量大時極其緩慢。
解決:給高頻查詢的字段加索引。
舉例:
-- 未優化:全表掃描(假設users表有10萬行,name無索引)
SELECT * FROM users WHERE name='小明';
-- 優化:給name加索引(執行一次,後續查詢受益)
CREATE INDEX idx_name ON users(name);
-- 優化後:數據庫直接通過索引定位數據,type從ALL變爲ref(EXPLAIN可驗證)
注意:
- 索引不是越多越好!寫得越多,插入/更新/刪除時維護索引的成本越高(比如用戶表的id主鍵默認有索引,無需重複建)。
- 優先給“重複值少、查詢條件多”的字段加索引(如user_id比username(可能重名)更合適)。
技巧2:避免SELECT *,只取需要的字段¶
問題:SELECT *會返回表中所有字段,包括大字段(如text類型),導致IO效率極低。
解決:明確列出需要的字段。
舉例:
-- 錯誤:返回所有字段,包含大文本等冗餘數據
SELECT * FROM orders;
-- 優化:只取核心字段(如id、order_no、amount)
SELECT id, order_no, amount FROM orders;
效果:數據量越大,SELECT *的劣勢越明顯,減少字段能直接降低網絡傳輸和內存佔用。
技巧3:優化JOIN操作:小表驅動大表¶
問題:JOIN多個表時,表的連接順序錯誤會導致“大表被全表掃描”。
解決:用小表驅動大表(先過濾小表,再關聯大表),且優先用INNER JOIN(只保留匹配的數據)。
舉例:
-- 錯誤:大表orders在前,先全表掃描大表,再關聯小表order_items
SELECT o.id, oi.product_id FROM orders o LEFT JOIN order_items oi ON o.id=oi.order_id WHERE o.status='已完成';
-- 優化:先過濾orders小表(假設status='已完成'的數據少),再關聯order_items大表
SELECT o.id, oi.product_id FROM
(SELECT id FROM orders WHERE status='已完成') o -- 小表
LEFT JOIN order_items oi ON o.id=oi.order_id; -- 再關聯大表
原理:數據庫JOIN時會以“左表”爲基準,小表數據少,遍歷次數更少,效率更高。
技巧4:別在索引字段上用函數¶
問題:在WHERE條件中對索引字段用函數(如YEAR()、DATE()),會導致索引失效,重新全表掃描。
錯誤舉例:
SELECT * FROM sales WHERE YEAR(sale_date)=2023; -- sale_date的索引被YEAR()函數“破壞”
解決:把函數邏輯移到字段本身,避免索引失效。
優化後:
-- 用BETWEEN代替函數,讓索引生效
SELECT * FROM sales WHERE sale_date BETWEEN '2023-01-01' AND '2023-12-31';
技巧5:用EXPLAIN分析查詢計劃(關鍵!)¶
新手必學工具:EXPLAIN能幫你“看穿”SQL執行過程,快速定位問題。執行EXPLAIN + SQL,看輸出的type列和Extra列:
- type列:ALL(全表掃描,差!改!)、ref(走索引,優)、eq_ref(主鍵關聯,最好)。
- Extra列:Using filesort(排序無索引)、Using temporary(創建臨時表)—— 遇到這些要警惕!
舉例:
EXPLAIN SELECT * FROM users WHERE name='小明';
如果type是ALL,說明全表掃描;如果是ref,說明索引生效,查詢快。
三、3個常見誤區(避開就能少踩坑)¶
-
誤區1:索引越多越好
索引會加速查詢,但會拖慢插入/更新/刪除。比如給users表的status(只有“0/1/2”三個值)建索引,反而讓每次更新都要維護索引,得不償失。 -
誤區2:OR條件導致索引失效
用OR連接條件時,可能無法同時走多個索引。例如:
SELECT * FROM users WHERE id=1 OR name='張三'; -- 可能無法用id的索引
替代方案:用UNION ALL拆分條件(如果兩個字段的索引可以獨立使用):
(SELECT * FROM users WHERE id=1) UNION ALL (SELECT * FROM users WHERE name='張三');
- 誤區3:COUNT(*) = 快
COUNT(*)統計行數很快(MySQL會直接走索引計數),但COUNT(DISTINCT name)會慢(需去重)。如果不需要去重,用COUNT(1)或COUNT(*)即可。
四、總結:從小技巧開始,逐步優化¶
- 先查再優化:用
EXPLAIN定位全表掃描、索引失效等問題。 - 基礎技巧優先:加索引、
SELECT指定字段、優化JOIN順序。 - 避免重複造輪子:網上已有很多優化案例,遇到問題多搜“EXPLAIN分析”“索引失效”等關鍵詞。
記住:查詢優化不是“玄學”,而是基於“減少數據處理量+合理利用索引”的科學方法。掌握這些基礎技巧,你就能寫出“一看就快”的SQL啦!