添加小編微信帶您進入Java交流社區
小編微信:372787553 備註進羣
Extra 輔助信息說明
該Extra
列 EXPLAIN
輸出包含MySQL解決查詢的額外信息。以下列表說明了可以在此列中顯示的值。每個項目還針對JSON格式的輸出指示哪個屬性顯示Extra
值。對於其中一些,有一個特定的屬性。其他顯示爲message
屬性的文本。
如果你想使你的查詢儘可能快,看出來Extra
的列值Using filesort
和Using temporary
,或在JSON格式的EXPLAIN
輸出,用於 using_filesort
和 using_temporary_table
性能等於 true
。
-
Child of
tablepushed join@1
(JSON:message
文本)該表是*
table
*可以向下推到NDB內核的聯接中的子級引用 。啓用下推聯接時,僅適用於NDB羣集。 -
const row not found
(JSON屬性:const_row_not_found
)對於查詢,該表爲空。
SELECT ... FROM tbl_name
-
Deleting all rows
(JSON屬性:message
)對於
DELETE
,某些存儲引擎(如MyISAM
)支持一種處理程序方法,該方法以一種簡單而快速的方式刪除所有錶行。Extra
如果引擎使用此優化,則顯示此值。 -
Distinct
(JSON屬性:distinct
)MySQL正在尋找不同的值,因此在找到第一個匹配的行後,它將停止爲當前行組合搜索更多行。
-
FirstMatch
(tbl_name)JSON屬性:
first_match)半連接FirstMatch連接快捷方式策略用於*
tbl_name
*。 -
Full scan on NULL key
(JSON屬性:message
)當優化器無法使用索引查找訪問方法時,這會作爲子查詢優化的後備策略而發生。
-
Impossible HAVING
(JSON屬性:message
)該
HAVING
子句始終爲false,無法選擇任何行。 -
Impossible WHERE
(JSON屬性:message
)該
WHERE
子句始終爲false,無法選擇任何行。 -
Impossible WHERE noticed after reading const tables
(JSON屬性:message
)MySQL已經讀取了所有
const
(和system
)表,並注意到該WHERE
子句始終爲false。 -
LooseScan
(m … n) (JSON屬性:message
)使用半連接的LooseScan策略。 *
m
*和 *n
*是關鍵零件號。 -
No matching min/max row
(JSON屬性:message
)沒有行滿足查詢的條件,例如 。
SELECT MIN(...) FROM ... WHERE
condition -
no matching row in const table
(JSON屬性:message
)對於具有聯接的查詢,存在一個空表或一個表中沒有滿足唯一索引條件的行。
-
No matching rows after partition pruning
(JSON屬性:message
)對於
DELETE
或UPDATE
,優化器在分區修剪後找不到要刪除或更新的內容。它的含義類似於Impossible WHERE
forSELECT
語句。 -
No tables used
(JSON屬性:message
)查詢沒有
FROM
子句,或者有FROM DUAL
子句。對於
INSERT
或REPLACE
語句,EXPLAIN
在沒有任何SELECT
部分時顯示此值。例如,出現的EXPLAIN INSERT INTO t VALUES(10)
原因是因爲等同於EXPLAIN INSERT INTO t SELECT 10 FROM DUAL
。 -
Not exists
(JSON屬性:message
)MySQL能夠對
LEFT JOIN
查詢進行優化,並且在找到符合LEFT JOIN
條件的一行後,不檢查該表中的更多行是否爲上一行。這是可以通過這種方式優化的查詢類型的示例:SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
假設
t2.id
定義爲NOT NULL
。在這種情況下,MySQL 使用的值 掃描t1
並查找行 。如果MySQL在中找到匹配的行 ,它將知道它 永遠不會是 ,並且不會掃描具有相同值的其餘行。換句話說,對於in中的每一行,MySQL 實際上只需進行一次查找,無論in中實際匹配多少行。t2``t1.id``t2``t2.id``NULL``t2``id``t1``t2``t2
-
Plan isn't ready yet
(JSON屬性:無)EXPLAIN FOR CONNECTION
當優化器尚未完成爲在命名連接中執行的語句創建執行計劃時, 就會出現此值。如果執行計劃輸出包含多行,則Extra
取決於優化程序確定完整執行計劃的進度,其中任何一行或所有行都可以具有此 值。 -
Range checked for each record (index map: *
N*)
(JSON屬性:message
)MySQL找不到很好的索引來使用,但是發現一些索引可以在已知先前表中的列值之後使用。對於上表中的每個行組合,MySQL檢查是否可以使用
range
或index_merge
訪問方法來檢索行。這不是很快,但是比完全沒有索引的連接要快。適用標準如“範圍優化”和 “索引合併優化”中所述,除了上表的所有列值都是已知的並且被視爲常量。索引從1開始編號,其順序
SHOW INDEX
與表中顯示的順序相同。索引圖值 *N
*是指示哪些索引爲候選的位掩碼值。例如,值0x19
(二進制11001)表示將考慮索引1、4和5。 -
Scanned *
N* databases
(JSON屬性:message
)這表示在處理
INFORMATION_SCHEMA
表查詢時服務器執行了多少目錄掃描 ,如“優化INFORMATION_SCHEMA查詢”中所述。的值*N
*可以是0、1或all
。 -
Select tables optimized away
(JSON屬性:message
)優化器確定1)最多應返回一行,以及2)要生成該行,必須讀取確定的行集。當在優化階段可以讀取要讀取的行時(例如,通過讀取索引行),則在查詢執行期間無需讀取任何表。
當查詢被隱式分組(包含聚合函數但沒有
GROUP BY
子句)時,滿足第一個條件 。當每個使用的索引執行一次行查找時,滿足第二個條件。讀取的索引數決定了要讀取的行數。考慮以下隱式分組查詢:
SELECT MIN(c1), MIN(c2) FROM t1;
假設
MIN(c1)
可以通過讀取一個索引行MIN(c2)
來檢索,並且可以通過從另一索引中讀取一行來進行檢索。即,對於每一列c1
和c2
,存在其中列是索引的第一列的索引。在這種情況下,將通過讀取兩個確定性行來返回一行。Extra
如果要讀取的行不確定,則不會出現 此值。考慮以下查詢:SELECT MIN(c2) FROM t1 WHERE c1 <= 10;
假設這
(c1, c2)
是一個覆蓋指數。使用此索引,c1 <= 10
必須掃描所有具有的行以找到最小值c2
。相比之下,請考慮以下查詢:SELECT MIN(c2) FROM t1 WHERE c1 = 10;
在這種情況下,第一個索引行
c1 = 10
包含最小值c2
。僅一行必須讀取才能產生返回的行。對於維護每個表的行數準確的存儲引擎(例如
MyISAM
,但不是InnoDB
),對於缺少該子句或始終爲true且沒有 子句的查詢,Extra
可能會出現此值。(這是一個隱式分組查詢的實例,其中存儲引擎影響是否可以讀取確定數量的行。)COUNT(*)``WHERE``GROUP BY
-
Skip_open_table
,Open_frm_only
,Open_full_table
(JSON屬性:message
)這些值指示適用於
INFORMATION_SCHEMA
表查詢的文件打開優化,如“優化INFORMATION_SCHEMA查詢”中所述。Skip_open_table
:不需要打開表文件。通過掃描數據庫目錄,該信息已在查詢中可用。Open_frm_only
:僅.frm
需要打開表的文件。Open_full_table
:未優化的信息查找。的.frm
,.MYD
和.MYI
文件必須被打開。
-
Start temporary
,End temporary
(JSON屬性:message
)這表明臨時表用於半聯接重複淘汰策略。
-
unique row not found
(JSON屬性:message
)對於諸如的查詢,沒有行滿足 索引或表中的條件。
SELECT ... FROM *
tbl_name*``UNIQUE``PRIMARY KEY
-
Using filesort
(JSON屬性:using_filesort
)MySQL必須額外進行一遍,以找出如何按排序順序檢索行。排序是通過根據聯接類型遍歷所有行並存儲與該
WHERE
子句匹配的所有行的排序鍵和指向該行的指針來完成的。然後對鍵進行排序,並按排序順序檢索行。 -
Using index
(JSON屬性:using_index
)僅使用索引樹中的信息從表中檢索列信息,而不必進行其他查找以讀取實際行。當查詢僅使用屬於單個索引的列時,可以使用此策略。
對於
InnoDB
具有用戶定義的聚集索引的表,即使列中Using index
不存在 該索引也可以使用Extra
。如果type
isindex
和key
is 就是這種情況PRIMARY
。 -
Using index condition
(JSON屬性:using_index_condition
)通過訪問索引元組並首先對其進行測試以確定是否讀取完整的錶行來讀取表。這樣,除非必要,否則索引信息將用於延遲(“ 下推 ”)讀取整個錶行。
-
Using index for group-by
(JSON屬性:using_index_for_group_by
)與
Using index
表訪問方法類似,Using index for group-by
表示MySQL找到了一個索引,該索引可用於檢索aGROUP BY
或DISTINCT
查詢的所有列,而無需對實際表進行任何額外的磁盤訪問。此外,以最有效的方式使用索引,因此對於每個組,僅讀取少數索引條目。 -
Using join buffer (Block Nested Loop)
,Using join buffer (Batched Key Access)
(JSON屬性:using_join_buffer
)來自較早聯接的表被部分讀取到聯接緩衝區中,然後從緩衝區中使用它們的行來執行與當前表的聯接。
(Block Nested Loop)
表示使用塊嵌套循環算法,並(Batched Key Access)
表示使用批處理密鑰訪問算法。也就是說,將EXPLAIN
緩衝輸出前行中的表中的鍵 ,並從出現行所在的表中批量提取匹配的行Using join buffer
。在JSON格式的輸出中,的值
using_join_buffer
始終爲Block Nested Loop
或之一Batched Key Access
。 -
Using MRR
(JSON屬性:message
)使用多範圍讀取優化策略讀取表。
-
Using sort_union(...)
,Using union(...)
,Using intersect(...)
(JSON屬性:message
)這些指示了特定算法,該算法顯示瞭如何針對
index_merge
聯接類型合併索引掃描 。 -
Using temporary
(JSON屬性:using_temporary_table
)爲了解決該查詢,MySQL需要創建一個臨時表來保存結果。如果查詢包含
GROUP BY
和ORDER BY
子句以不同的方式列出列,通常會發生這種情況。 -
Using where
(JSON屬性:attached_condition
)甲
WHERE
子句用於限制來匹配下一個表或發送到客戶端的行。除非您特別打算從表中獲取或檢查所有行,否則如果查詢中的Extra
值不是Using where
並且表連接類型爲ALL
或 ,則 查詢中可能會出錯index
。Using where
在JSON格式的輸出中沒有直接對應的內容;該attached_condition
屬性包含使用的任何WHERE
條件。 -
Using where with pushed condition
(JSON屬性:message
)此產品適用於
NDB
表只。這意味着NDB Cluster正在使用條件下推優化來提高在非索引列和常量之間進行直接比較的效率。在這種情況下,條件被“ 下推 ”到羣集的數據節點,並同時在所有數據節點上進行評估。這樣就無需通過網絡發送不匹配的行,並且在可以但不使用條件下推的情況下,可以將此類查詢的速度提高5到10倍。 -
Zero limit
(JSON屬性:message
)該查詢有一個
LIMIT 0
子句,不能選擇任何行。
解釋輸出解釋
通過獲取輸出rows
列中值的乘積,可以很好地表明聯接的良好程度EXPLAIN
。這應該大致告訴您MySQL必須檢查多少行才能執行查詢。如果使用max_join_size
系統變量限制查詢,則 此行乘積還用於確定SELECT
執行哪些多表語句以及中止哪個多表語句。
以下示例顯示瞭如何根據提供的信息逐步優化多表聯接 EXPLAIN
。
假設您在SELECT
此處顯示了該 語句,並計劃使用進行檢查 EXPLAIN
:
EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,
tt.ProjectReference, tt.EstimatedShipDate,
tt.ActualShipDate, tt.ClientID,
tt.ServiceCodes, tt.RepetitiveID,
tt.CurrentProcess, tt.CurrentDPPerson,
tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
et_1.COUNTRY, do.CUSTNAME
FROM tt, et, et AS et_1, do
WHERE tt.SubmitTime IS NULL
AND tt.ActualPC = et.EMPLOYID
AND tt.AssignedPC = et_1.EMPLOYID
AND tt.ClientID = do.CUSTNMBR;
對於此示例,進行以下假設:
-
被比較的列已聲明如下。
表 列 數據類型 tt
ActualPC
CHAR(10)
tt
AssignedPC
CHAR(10)
tt
ClientID
CHAR(10)
et
EMPLOYID
CHAR(15)
do
CUSTNMBR
CHAR(15)
-
這些表具有以下索引。
表 指數 tt
ActualPC
tt
AssignedPC
tt
ClientID
et
EMPLOYID
do
CUSTNMBR
-
這些
tt.ActualPC
值分佈不均。
最初,在執行任何優化之前,該 EXPLAIN
語句會產生以下信息:
table type possible_keys key key_len ref rows Extra
et ALL PRIMARY NULL NULL NULL 74
do ALL PRIMARY NULL NULL NULL 2135
et_1 ALL PRIMARY NULL NULL NULL 74
tt ALL AssignedPC, NULL NULL NULL 3872
ClientID,
ActualPC
Range checked for each record (index map: 0x23)
因爲type
是 ALL
針對每個表的,所以此輸出表明MySQL正在生成所有表的笛卡爾積;也就是說,行的每種組合。這需要相當長的時間,因爲必須檢查每個表中的行數的乘積。對於當前情況,此乘積爲74×2135×74×3872 = 45,268,558,720行。如果桌子更大,您只能想象需要多長時間。
這裏的一個問題是,如果將索引聲明爲相同的類型和大小,則MySQL可以更有效地在列上使用索引。在這種情況下,VARCHAR
與 CHAR
被認爲是相同的,如果它們被聲明爲相同的大小。 tt.ActualPC
聲明爲 CHAR(10)
和et.EMPLOYID
是CHAR(15)
,因此長度不匹配。
要解決此列長度之間的差異,請使用 從10個字符ALTER TABLE
延長 ActualPC
到15個字符:
mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);
現在tt.ActualPC
和 et.EMPLOYID
都是 VARCHAR(15)
。EXPLAIN
再次執行該 語句將產生以下結果:
table type possible_keys key key_len ref rows Extra
tt ALL AssignedPC, NULL NULL NULL 3872 Using
ClientID, where
ActualPC
do ALL PRIMARY NULL NULL NULL 2135
Range checked for each record (index map: 0x1)
et_1 ALL PRIMARY NULL NULL NULL 74
Range checked for each record (index map: 0x1)
et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
這不是完美的,但是更好:rows
值的乘積 少了74倍。此版本在幾秒鐘內執行。
可以進行第二種更改以消除tt.AssignedPC = et_1.EMPLOYID
和tt.ClientID = do.CUSTNMBR
比較的列長不匹配:
mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
MODIFY ClientID VARCHAR(15);
修改之後, EXPLAIN
產生如下所示的輸出:
table type possible_keys key key_len ref rows Extra
et ALL PRIMARY NULL NULL NULL 74
tt ref AssignedPC, ActualPC 15 et.EMPLOYID 52 Using
ClientID, where
ActualPC
et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
在這一點上,查詢儘可能地被優化。剩下的問題是,默認情況下,MySQL假定該tt.ActualPC
列中的值是均勻分佈的,而表則不是這種情況tt
。幸運的是,很容易告訴MySQL分析密鑰分佈:
mysql> ANALYZE TABLE tt;
使用其他索引信息,聯接是完美的,並 EXPLAIN
產生以下結果:
table type possible_keys key key_len ref rows Extra
tt ALL AssignedPC NULL NULL NULL 3872 Using
ClientID, where
ActualPC
et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
在rows
從輸出列 EXPLAIN
是一個受過教育的猜測從MySQL聯接優化。通過將rows
乘積與查詢返回的實際行數進行比較,檢查數字是否接近真實 值。如果數字完全不同,則可以通過STRAIGHT_JOIN
在 SELECT
語句中使用並嘗試在FROM
子句中以不同順序列出表來 獲得更好的性能 。(但是,STRAIGHT_JOIN
由於它禁用了半聯接轉換, 可能會阻止使用索引。
在某些情況下,可能會執行EXPLAIN SELECT
與子查詢一起使用時會修改數據的語句。
本文的分享暫時就到這裏,希望對您有所幫助
關注 Java有貨領取更多資料
聯繫小編。微信:372787553,帶您進羣互相學習
左側小編微信,右側獲取免費資料
- SpringCloud 自定義封裝架構https://github.com/yanghaiji/javayh-platform
- Java 設計模式學習代碼 https://github.com/yanghaiji/design-pattern
- SpringCloud學習代碼: https://github.com/yanghaiji/javayh-cloud
- AlibabaCloud學習代碼:https://github.com/yanghaiji/javayh-cloud-nacos
- SpringBoot+Mybatis 多數據源切換:https://github.com/yanghaiji/javayh-boot-data-soure
- Redis、Mongo、Rabbitmq、Kafka學習代碼: https://github.com/yanghaiji/javayh-middleware
- SpringBoot+SpringSecurity實現自定義登錄學習代碼:https://github.com/yanghaiji/javayh-distribution