查詢成本組成有哪些。
- 1.I/O成本
- 2.CPU成本
- 3.Mysql規定讀取一個頁面花費的成本默認是1.0,讀取以及檢測一條記錄是否符合搜索條件的成本默認是0.2。1.0、0.2這些數字稱之為成本常數
- 4.需要注意的是,不管讀取記錄時需不需要檢測是否滿足搜索條件,其成本都算是0.2。
單表查詢的成本
基於成本的優化步驟
- 1.在一條單表查詢語句真正執行之前,MySQL的查詢優化器會找出執行該語句所有可能使用的方案,對比之后找出成本最低的方案--這個成本最低的方案就是所謂的執行計划
- 2.具體流程如下:
- 3.根據搜索條件,找出所有可能使用的索引
- 4.計算全表掃描的代價
- 5.計算使用不同索引執行查詢的代價
- 6.對比各種執行方案的代價,找出成本最低的那一個
根據搜索條件,找出所有可能使用的索引
- 1.一個查詢中可能使用到的索引稱之為possible keys。
計算全表掃描的代價
- 1.聚簇索引占用的頁面數
- 2.該表中的記錄數
- 3.MySQL為每個表維護了一系列的統計信息,上述1和2的信息就在這里面。
- 4.可以通過SHOW TABLE STATUS LIKE tableName 來查詢
- 5.Rows代表記錄--在innodb下只是一個概數。
- 6.Data_length--表示表占用的存儲空間字節數。
- 7.Data_length = 聚簇索引的頁面數量 x 每個頁面的大小(16KB)
- 8.I/O成本==頁面數量*1.0+1.1
- 9.CPU成本=ROWS*0.2+1.0--0.2指的是訪問一條記錄所需的成本常數
- 10.總成本=I/O成本+CPU成本。
- 11.我們前邊說過表中的記錄其實都存儲在聚簇索引對應B+樹的葉子節點中,所以只要我們通過根節點獲得了最左邊的葉子節點,就可以沿着葉子節點組成的雙向鏈表把所有記錄都查看一遍
。也就是說全表掃描這個過程其實有的B+樹內節點是不需要訪問的.上述計算全表掃描是個比較粗略的計算。
計算使用不同索引執行查詢的代價
- 1.要分別分析單獨使用這些索引執行查詢的成本,最后還要分析是否可能使用到索引合並
- 2.MySQL查詢優化器先分析使用唯一二級索引的成本,再分析使用普通索引的成本---當然這個前提是無法直接走主鍵索引。
- 3.對於使用二級索引 + 回表方式的查詢:主要考慮范圍區間數量和需要回表的記錄數。
- 4.范圍區間數量:不論某個范圍區間的二級索引到底占用了多少頁面,查詢優化器粗暴的認為讀取索引的一個范圍區間的I/O成本和讀取一個頁面是相同的
- 5.需要回表的記錄數:首先通過左右區間可以在常數范圍找到臨界點記錄。然后只要從區間最左記錄沿着鏈表方向走向區間最右記錄。如果兩者相隔不超過10個頁面
是可以得到回表的准確數據。如果超過則統計10個頁面情況下平均每個頁面包含的記錄數,然后再乘以頁面個數。 - 6.尋找頁面數,只要去記錄也得父層尋找即可。
- 7.CPU成本主要是讀取二級索引記錄的成本 + 讀取並檢測回表后聚簇索引記錄的成本
index dive
- 1.Mysql把這種通過直接訪問索引對應的B+樹來計算某個范圍區間對應的索引記錄條數的方式稱之為index dive
- 2.當我們使用二級索引in的時候,由於不是唯一的,所以在in中的每一個參數都需要index dive
- 3.mysql通過eq_range_index_dive_limit參數,如果是in的話 參數數量大於這個參數 則采用索引統計數據來進行估算記錄數量。
- 4.主要使用ROWS 和Cardinality,兩者可以計算出一個值得重復次數==一個值的重復次數 ≈ Rows ÷ Cardinality
- 5.所以一個in中一個參數代表10個記錄
mysql為索引的統計數據
- 1.MySQL也會為表中的每一個索引維護一份統計數據---- SHOW INDEX FROM TABLENAME
- 2.關鍵的屬性:Cardinality,Sub_part
- 3.Cardinality:表示索引列中不重復值的個數,這是一個估數。 值越大代表該列重復值越少。值越大重復越小,則可區分度就很大,進而建立索引的意義不大。
- 4.Sub_part:對於存儲字符串或者字節串的列來說,有時候我們只想對這些串的前n個字符或字節建立索引,這個屬性表示的就是那個n值。如果對完整的列建立索引的話,該屬性的值就是NULL。
連接查詢的成本
- 1.MySQL中連接查詢采用的是嵌套循環連接算法,驅動表會被訪問一次,被驅動表可能會被訪問多次
- 2.查詢成主要是 :單次查詢驅動表的成本和多次查詢被驅動表的成本(具體查詢多少次取決於對驅動表查詢的結果集中有多少條記錄)
- 3.驅動表進行查詢后得到的記錄條數稱之為驅動表的扇出(英文名:fanout)
Condition filtering
- 1.當使用的是全表掃描的方式執行的單表查詢,那么計算驅動表扇出時需要猜滿足搜索條件的記錄到底有多少條。
- 2.如果使用的是索引執行的單表掃描,那么計算驅動表扇出的時候需要猜滿足除使用到對應索引的搜索條件外的其他搜索條件的記錄有多少條。
兩表連接的成本分析
- 1.連接查詢總成本 = 單次訪問驅動表的成本 + 驅動表扇出數 x 單次訪問被驅動表的成本
- 2.對於左(外)連接和右(外)連接查詢來說,它們的驅動表是固定的,所以想要得到最優的查詢方案只需要:分別為驅動表和被驅動表選擇成本最低的訪問方法。
- 3.對於內連接來說,驅動表和被驅動表的位置是可以互換的,因此算出最優的方式執行。
多表連接的成本分析
- 1.有n個表進行連接,MySQL查詢優化器要每一種連接順序的成本都計算一遍么?
- 2.提前維護一個最小成本值,每個連接順序查詢成本計算時只要大於這個的直接跳過。
- 3.系統變量optimizer_search_depth,可以規定最多窮舉多少種查詢方式。
- 4.根據某些規則壓根兒就不考慮某些連接順序--這些規則叫啟發規則,可以通過系統變量optimizer_prune_level來控制到底是不是用這些啟發式規則。
調節成本常數
- 1.讀取一個頁面花費的成本默認是1.0
- 2.測一條記錄是否符合搜索條件的成本默認是0.2
- 3.其實除了這兩個成本常數,MySQL還支持好多呢,它們被存儲到了mysql數據庫的兩個表中:engine_cost 和server_cost 。
- 4.一條語句的執行其實是分為兩層的:server層,存儲引擎層
- 5.通過update 修改常數,然后通過FLUSH OPTIMIZER_COSTS;生效
作者:簡書徐小耳
鏈接:https://www.jianshu.com/p/aecdcc2babdd
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。