【黑魔法】Covering Indexes、STRAIGHT_JOIN

今天給你們介紹兩個黑魔法,這都是壓箱底的法寶。你們在使用時,必定要弄清他們的適用場景及用法,用好了,就是一把開天斧,用很差那就是多此一舉。自從看過耗子哥(左耳朵耗子)的博客,都會給對相應專題有興趣的小夥伴列出幾篇拓展文章,我以爲這種方式仍是很是不錯,因此這篇文章我也會列出幾篇擴展的文章,供想更深刻思考的小夥伴查閱。html

可能有人會認爲這兩個用法會比較冷門,可是在跨系統調用api的過程當中,表的數據量比較大時,sql查詢性能太差,會致使接口響應超時,就會對相應的業務產生很是大的影響。系統優化,你們千萬不要覺得只是後端的代碼優化而已,sql的優化一樣也是重點mysql

1.Covering Indexes

可能有小夥伴會問,Covering Indexes究竟是什麼神器呢?它又是如何來提高性能的呢?接下來我會用最通俗易懂的語言來進行介紹,畢竟不是每一個程序猿都要像DBA那樣深入理解數據庫,知道如何用以及如何用好神器纔是最關鍵的。sql

Covering Indexes就是一個索引覆蓋全部要查詢的字段(ps:這句話我挖個坑,文末我來解釋)。數據庫

An index that contains all required information to resolve the query is known as a 「Covering Index」 – it completely covers the query.
Covering Index includes all the columns, the query refers to in the SELECT, JOIN, and WHERE clauses.

接下來咱們經過一個很是簡單的sql來進行分析:後端

SELECT column1, column2 FROM tablename WHERE column3=xxx;

你能想象將sql的執行時間從1.8秒,降到1.2秒,繼續壓榨到0.5,0.2.....,酣暢淋漓,怎一個爽字了得。就跟排兵佈陣同樣,打勝仗當然重要,但得想出成本最低效果最好的陣法,定會收穫滿滿的成就感。api

這條sql要如何來進行優化呢?第一反應可能就是說給「column3」加索引(普通索引或惟一索引)啊,沒錯,這樣確實能在很大程度上提高這條sql的性能。mysql優化

咱們來分析下上面sql的執行計劃:由於給「column3」建了索引,就會快速根據這個索引查詢到符合條件的結果;而後再去這些符合條件的結果裏查找所需的column一、column2字段;請注意,整個過程出現了兩次查詢,一次是查詢索引,另外一次查詢結果的所需字段。性能

那能不能將上面說的執行計劃再優化一下呢?大殺器Covering Indexes就是用來幹這事的。給column三、column一、column2建個複合索引,以下:大數據

alter table table_name add index index_column3 (column3,column1,column2) ;

 這樣就能夠直接經過索引就能查詢出符合條件的數據,而沒必要像上面那樣先去查索引,而後再去查數據的兩個過程優化

光說不練那是假把式!小夥伴們能夠用explain去試試上面的兩種狀況,若是執行復合索引後的狀況,你會發現Extra裏出現Using index。

剛開始我說挖了個坑,如今我把坑填上。既然神器Covering Indexes這麼好用,之後select語句的我都無論三七二十一的都亮出神器。難不成你select *也要亮神器?一個表那麼多字段,全建成索引?那索引文件會不堪重負的,這就會拔苗助長,帶來一系列惡果的。索引文件過大會形成insert、update很是慢,你select卻是爽快了,不能不顧其餘兄弟吧,不仗義的事咱不能幹,切記!

若是看完這個分析還不過癮,下面我給幾篇擴展文章:

https://www.c-sharpcorner.com/UploadFile/b075e6/improving-sql-performance-using-covering-indexes/

https://www.red-gate.com/simple-talk/sql/learn-sql-server/using-covering-indexes-to-improve-query-performance/

https://stackoverflow.com/questions/609343/what-are-covering-indexes-and-covered-queries-in-sql-server

https://stackoverflow.com/questions/62137/what-is-a-covered-index

 

2.STRAIGHT_JOIN

接下來給你們下另外一個性能提高神器-STRAIGHT_JOIN,在數據量大的聯表查詢中靈活運用的話,能大大縮短查詢時間。

首先來解釋下STRAIGHT_JOIN究竟是用作什麼的:

STRAIGHT_JOIN is similar to JOIN, except that the left table is always read before the right table. 
This can be used for those (few) cases for which the join optimizer puts the tables in the wrong order.

意思就是說STRAIGHT_JOIN功能同join相似,但能讓左邊的表來驅動右邊的表,能改表優化器對於聯表查詢的執行順序。

接下來咱們舉個例子進行大體的分析:

select t1.*
from Table1 t1
inner join Table2 t2
on t1.CommonID = t2.CommonID
where t1.FilterID = 1

以上sql大數據量下執行須要30s,是否是很奇怪?明明Table1表的FilterID字段建了索引啊,Table1和Table2的CommonID也建了索引啊。經過explain來分析,你會發現執行計劃中表的執行順序是Table2->Table1。這個時候要略微介紹下驅動表的概念,mysql中指定了鏈接條件時,知足查詢條件的記錄行數少的表爲驅動表;如未指定查詢條件,則掃描行數少的爲驅動表。mysql優化器就是這麼粗暴以小表驅動大表的方式來決定執行順序的

但以下sql的執行時間都少於1s:

select t1.*
from Table1 t1
where t1.FilterID = 1

select t1.*
from Table1 t1
inner join Table2 t2
on t1.CommonID = t2.CommonID

這個時候STRAIGHT_JOIN就派上用場,咱們對sql進行改造以下:

select t1.*
from Table1 t1
STRAIGHT_JOIN  Table2 t2
on t1.CommonID = t2.CommonID
where t1.FilterID = 1

用explain進行分析,發現執行順序爲Table1->Table2,這時就由Table1來做爲驅動表了,Table1中相應的索引也就用上了,執行時間居然低於1s了。

分析到這裏,必需要重點說下:

  • STRAIGHT_JOIN只適用於inner join,並不使用與left join,right join。(由於left join,right join已經表明指定了表的執行順序)
  • 儘量讓優化器去判斷,由於大部分狀況下mysql優化器是比人要聰明的。使用STRAIGHT_JOIN必定要慎重,由於啊部分狀況下認爲指定的執行順序並不必定會比優化引擎要靠譜。

擴展閱讀:

https://stackoverflow.com/questions/512294/when-to-use-straight-join-with-mysql

https://stackoverflow.com/questions/5818837/why-does-straight-join-so-drastically-improve-this-query-and-what-does-it-mean

https://dev.mysql.com/doc/refman/8.0/en/join.html

相關文章
相關標籤/搜索