1. 為什么要建索引?索引一定能提高性能嗎?
場景:一個表有上千萬數據,查詢
SELECT * FROM user WHERE age=25;
。問題:沒有索引時會全表掃描,性能差。
解決方案:
給
age
建立普通索引,加快查詢。但是索引不是越多越好:
插入、更新會更慢(需要維護索引)。
索引在選擇性差(如
gender
字段只有男女)時可能沒效果。
2. 覆蓋索引是什么?為什么快?
場景:查詢用戶 ID 列表:
SELECT id FROM user WHERE age = 25;
說明:如果
age
上有索引,且查詢只需要返回id
(在索引樹中已包含),就不用回表。優化點:建組合索引
(age, id)
,查詢時只走索引層,不訪問數據頁。
3. COUNT(*)
為什么慢?如何優化?
場景:統計
order
表的總數,有上千萬行。問題:
COUNT(*)
會逐行掃描統計。優化方法:
如果是估算:用
EXPLAIN
的rows
。如果是精確計數:可以做 冗余表 或 緩存(Redis)。
InnoDB 會遍歷二級索引+主鍵,不像 MyISAM 有行數緩存。
4. SQL 執行慢的常見原因?
場景:某個 SQL 在測試庫很快,但生產庫很慢。
常見原因:
沒有走索引,發生全表掃描。
走了索引但選擇性差,優化器放棄。
隱式轉換(
WHERE phone = 1380000
,字段是VARCHAR
)。統計信息不準。
解決:
查看
EXPLAIN
。強制索引
FORCE INDEX
。優化字段類型,避免隱式轉換。
更新統計信息
ANALYZE TABLE user;
5. 什么時候建組合索引?最左匹配原則怎么理解?
場景:經常有查詢:
SELECT * FROM user WHERE country = 'CN' AND age = 25;
說明:
建組合索引
(country, age)
,比單列索引效率高。最左匹配:索引從最左邊開始生效,
(a,b,c)
等價于(a)
、(a,b)
,但不會用(b)
單獨索引。
優化點:
多條件查詢,優先建組合索引。
條件字段順序,選擇性高的放前面。
6. 如何優化分頁查詢?
場景:
SELECT * FROM orders ORDER BY create_time LIMIT 100000, 20;
很慢,因為 MySQL 先掃描10萬行再丟棄。
優化方法:
記錄上一次的偏移:
SELECT * FROM orders WHERE id > 100000 LIMIT 20;
用覆蓋索引 + join:
SELECT o.* FROM orders o JOIN (SELECT id FROM orders ORDER BY id LIMIT 100000, 20) t ON o.id = t.id;
7. 為什么要分庫分表?分庫分表后怎么查?
場景:
user
表超過 1 億行,查詢、寫入都慢。優化思路:
分庫分表:按
user_id % 8
拆成 8 張表。查詢時通過中間件(ShardingSphere、Mycat)路由。
跨庫統計問題 → 用 中間件聚合 或 異步匯總表。
8. InnoDB 和 MyISAM 的區別?為什么選擇 InnoDB?
場景:設計電商訂單表。
區別:
InnoDB:支持事務、行鎖、MVCC,適合高并發。
MyISAM:表鎖、無事務、計數快,適合只讀場景。
面試要點:幾乎所有業務型系統用 InnoDB,因為數據安全更重要。
9. 大表優化思路?
場景:訂單表 5 億行,查詢和維護很慢。
優化點:
水平拆分(分庫分表)。
冷熱數據分離:歷史數據歸檔。
索引優化:只建必要索引。
讀寫分離:主庫寫,從庫讀。
緩存:Redis 緩存熱點數據。
10. 如何排查慢查詢?
步驟:
打開慢查詢日志:
slow_query_log = ON long_query_time = 1
用
EXPLAIN
分析執行計劃。觀察是否用到索引、rows 預估數。
用
SHOW PROFILE
查看耗時階段。實在不行,用
pt-query-digest
工具分析日志。