「黑魔法」mysql黑魔法Covering Indexes、STRAIGHT

「黑魔法」mysql黑魔法Covering Indexes、STRAIGHT_JOIN


今天給大家介紹兩個黑魔法,這都是壓箱底的法寶。大家在使用時,一定要弄清他們的適用場景及用法,用好了,就是一把開天斧,用不好那就是畫蛇添足。

1.Covering Indexes

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

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…..,酣暢淋漓,怎一個爽字了得。就跟排兵佈陣一樣,打勝仗固然重要,但得想出成本最低效果最好的陣法,定會收穫滿滿的成就感。

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

我們來分析下上面sql的執行計劃:因為給“column3”建了索引,就會快速根據這個索引查詢到符合條件的結果;然後再去這些符合條件的結果裡查找所需的column1、column2字段;請注意,整個過程出現了兩次查詢,一次是查詢索引,另一次查詢結果的所需字段。簡單點來說,就是根據column3找到符合條件的主鍵,然後根據主鍵找到該行數據,即可找到所需的column1、column2。在這個過程中,回到主鍵索引樹搜索的過程,稱為回表。

那能不能將上面說的執行計劃再優化一下呢?大殺器Covering Indexes就是用來幹這事的。給column3、column1、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

「黑魔法」mysql黑魔法Covering Indexes、STRAIGHT_JOIN


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
「黑魔法」mysql黑魔法Covering Indexes、STRAIGHT_JOIN


這個時候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


分享到:


相關文章: