下面是小凰凰的簡介,看下吧!
💗人生態度:珍惜時間,渴望學習,熱愛音樂,把握命運,享受生活
💗學習技能:網絡 -> 雲計算運維 -> python全棧( 當前正在學習中)
💗您的點贊、收藏、關注是對博主創作的最大鼓勵,在此謝過!
有相關技能問題可以寫在下方評論區,我們一起學習,一起進步。
後期會不斷更新python全棧學習筆記,秉着質量博文爲原則,寫好每一篇博文。
文章目錄
一、單表查詢優化
1、單表查詢的優化點
現在我創建一個單表,我相信理解這些應該不需要看錶了吧,針對問題,優化就完事了!
需求:查詢 category_id 爲1 且 comments 大於 1 的情況下,views 最多的 article_id。
很顯然,type 是 ALL,即全表掃描。Extra 裏還出現了 Using filesort(文件內排序)
2、開始優化
# 1.1 新建索引+刪除索引
# ALTER TABLE `article` ADD INDEX idx_article_ccv ( `category_id` , `comments`, `views` ); alter增加索引,我們採用下面的create方法
create index idx_article_ccv on article(category_id,comments,views);
# 1.2 第2次EXPLAIN
EXPLAIN SELECT id,author_id FROM `article` WHERE category_id = 1 AND comments >1 ORDER BY views DESC LIMIT 1;
# 結論:
# type 變成了 range,這是可以忍受的。但是 extra 裏使用 Using filesort 仍是無法接受的。
# 但是我們已經建立了索引,爲啥沒用呢?
# 這是因爲按照 BTree 索引的工作原理,
# 先排序 category_id,
# 如果遇到相同的 category_id 則再排序 comments,如果遇到相同的 comments 則再排序 views。
# 當 comments 字段在聯合索引裏處於中間位置時,
# 因comments > 1 條件是一個範圍值(所謂 range),
# MySQL 無法利用索引再對後面的 views 部分進行檢索,即 範圍類型查詢字段後面的索引無效。
# 1.3 刪除第一次建立的索引
DROP INDEX idx_article_ccv ON article;
# 1.4 第2次新建索引
create index idx_article_cv on article(category_id,views);
# 1.5 第3次EXPLAIN
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
# 結論:可以看到,type 變爲了 ref,Extra 中的 Using filesort 也消失了,結果非常理想。
二、雙表查詢優化
1、雙表查詢優化點分析
# 下面開始 explain 分析
EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
# 結論: type 有 All ,且雙表都是ALL,接下來我們需要加索引
# 那麼我們到底是選擇給那張表的card字段加索引呢?
2、開始優化
(1)左表建立索引(試優化)
# 添加索引優化
ALTER TABLE class ADD INDEX X (card);
# 第 2 次 explain
EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
有一定的優化,type由全表掃描變成了索引樹遍歷
!接下來我們看看右表card字段建立索引
!
(2)右表建立索引(試優化)
# 刪除舊索引 + 新建 + 第 3 次 explain
DROP INDEX X ON class;
ALTER TABLE `book` ADD INDEX Y ( `card`); # 給左連接的右表加索引
EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
可以看到第二行的 type 變爲了 ref,rows 也由20變成了1,優化比較明顯。
這是由左連接特性決定的。 LEFT JOIN 條件用於確定如何從右表搜索行 , 左邊一定都有 , 所以右邊是我們的關鍵點 , 一定需要建立索引。
3、雙表創建索引建議
- left join 時,選擇小表作爲驅動表,大表作爲被驅動表。
- 保證被驅動表的join字段已經被索引
- inner join 時,mysql 自動選擇小表作爲驅動表。因爲 驅動表無論如何都會被全表掃描。所以掃描次數越少越好
- 子查詢儘量不要放在被驅動表,有可能使用不到索引。
select a.name ,bc.name from t_emp a left join
(select b.id , c.name from t_dept b
inner join t_emp c on b.ceo = c.id )bc
on bc.id = a.deptid.
上段查詢中用到了子查詢,必然 bc 表沒有索引。肯定會進行全表掃描
上段查詢 可以直接使用 兩個 left join 優化
select a.name , c.name from t_emp a
left outer join t_dept b on a.deptid = b.id
left outer join t_emp c on b.ceo=c.id
所有條件都可以使用到索引
若必須用到子查詢,可將子查詢設置爲驅動表,,因爲驅動表的type 肯定是 all,而子查詢返回的結果表沒有索引,必定也是all
三、三表查詢優化
1、三表查詢優化點
2、開始優化
三表連接查詢,會出現連接緩存!按照兩個表的規律,分別建立兩個索引:
效果如下:
總結:
後2行的type都是ref且總的rows優化效果很好,效果不錯,因此索引最好設置在需要經常查詢的字段中。
join語句優化:永遠用小的結果集驅動大的結果集,即小表驅動大表
!
四、子查詢優化
建議先看下:https://blog.csdn.net/weixin_44571270/article/details/107027121
上述兩種方法結果一樣,但是一個使用的是in,一個使用的是exists
我們可以說in是子查詢驅動主查詢
,即先得出子查詢的結果,再去主查詢拿到id符合條件的記錄!
exists可以說是主查詢驅動子查詢
,先是遍歷主查詢得到結果,再拿着主查詢的結果,執行子查詢的where的條件是否成立,成立則返回True,不成立則返回False。因此exists的select語句並沒用,因此你可以隨便填!
因此得出結論:
1. 當子查詢的數據集小於主查詢的數據集,in優於exists
2. 當主查詢的數據集小於子查詢的數據集,exists優於in
爲什麼?'因爲必須符合小表驅動大表的原則!'
3. 至少驅動表的相應索引字段應該建立索引