免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
MySQL優(yōu)化(二) MySQL 卓越資源

MySQL優(yōu)化(二)

2007-06-24 23:24 來源: imysql.cn 作者:葉金榮 網(wǎng)友評論 0 條 瀏覽次數(shù) 99

7.2.1 EXPLAIN 語法(得到SELECT 的相關(guān)信息)

 

EXPLAIN tbl_name

或者:

EXPLAIN SELECT select_options

EXPLAIN 語句可以被當(dāng)作 DESCRIBE 的同義詞來用,也可以用來獲取一個MySQL要執(zhí)行的 SELECT 語句的相關(guān)信息。

  • EXPLAIN tbl_name 語法和 DESCRIBE tbl_nameSHOW COLUMNS FROM tbl_name 一樣。
  • 當(dāng)在一個 SELECT 語句前使用關(guān)鍵字 EXPLAIN 時,MYSQL會解釋了即將如何運行該 SELECT 語句,它顯示了表如何連接、連接的順序等信息。

 

本章節(jié)主要講述了第二種 EXPLAIN 用法。

EXPLAIN 的幫助下,您就知道什么時候該給表添加索引,以使用索引來查找記錄從而讓 SELECT 運行更快。

如果由于不恰當(dāng)使用索引而引起一些問題的話,可以運行 ANALYZE TABLE 來更新該表的統(tǒng)計信息,例如鍵的基數(shù),它能幫您在優(yōu)化方面做出更好的選擇。詳情請看"14.5.2.1 ANALYZE TABLE Syntax"。

您還可以查看優(yōu)化程序是否以最佳的順序來連接數(shù)據(jù)表。為了讓優(yōu)化程序按照 SELECT 語句中的表名的順序做連接,可以在查詢的開始使用 SELECT STRAIGHT_JOIN 而不只是 SELECT。

EXPLAIN 返回了一行記錄,它包括了 SELECT 語句中用到的各個表的信息。這些表在結(jié)果中按照MySQL即將執(zhí)行的查詢中讀取的順序列出來。MySQL用一次掃描多次連接(single-sweep, multi-join) 的方法來解決連接。這意味著MySQL從第一個表中讀取一條記錄,然后在第二個表中查找到對應(yīng)的記錄,然后在第三個表中查找,依次類推。當(dāng)所有的表都掃描完了,它輸出選擇的字段并且回溯所有的表,直到找不到為止,因為有的表中可能有多條匹配的記錄下一條記錄將從該表讀取,再從下一個表開始繼續(xù)處理。

在MySQL version 4.1中,EXPLAIN 輸出的結(jié)果格式改變了,使得它更適合例如 UNION 語句、子查詢以及派生表的結(jié)構(gòu)。更令人注意的是,它新增了2個字段: idselect_type。當(dāng)你使用早于MySQL 4.1的版本就看不到這些字段了。

EXPLAIN 結(jié)果的每行記錄顯示了每個表的相關(guān)信息,每行記錄都包含以下幾個字段:

 

 

id
本次 SELECT 的標(biāo)識符。在查詢中每個 SELECT 都有一個順序的數(shù)值。

 

 

select_type
SELECT 的類型,可能會有以下幾種:

 

 

 

SIMPLE
簡單的 SELECT (沒有使用 UNION 或子查詢)

 

PRIMARY
最外層的 SELECT。

 

UNION
第二層,在SELECT 之后使用了 UNION 。

 

DEPENDENT UNION
UNION 語句中的第二個 SELECT,依賴于外部子查詢

 

SUBQUERY
子查詢中的第一個 SELECT

 

DEPENDENT SUBQUERY
子查詢中的第一個 SUBQUERY 依賴于外部的子查詢

 

DERIVED
派生表 SELECTFROM 子句中的子查詢)

 

 

table
記錄查詢引用的表。

 

 

type
表連接類型。以下列出了各種不同類型的表連接,依次是從最好的到最差的:

 

 

system
表只有一行記錄(等于系統(tǒng)表)。這是 const 表連接類型的一個特例。

 

 

const
表中最多只有一行匹配的記錄,它在查詢一開始的時候就會被讀取出來。由于只有一行記錄,在余下的優(yōu)化程序里該行記錄的字段值可以被當(dāng)作是一個恒定值。const 表查詢起來非??欤驗橹灰x取一次!const 用于在和 PRIMARY KEYUNIQUE 索引中有固定值比較的情形。下面的幾個查詢中,tbl_name 就是 const 表了:

 

SELECT * FROM tbl_name WHERE primary_key=1;SELECT * FROM tbl_nameWHERE primary_key_part1=1 AND primary_key_part2=2;

 

 

eq_ref
從該表中會有一行記錄被讀取出來以和從前一個表中讀取出來的記錄做聯(lián)合。與 const 類型不同的是,這是最好的連接類型。它用在索引所有部分都用于做連接并且這個索引是一個 PRIMARY KEYUNIQUE 類型。eq_ref 可以用于在進(jìn)行"="做比較時檢索字段。比較的值可以是固定值或者是表達(dá)式,表達(dá)示中可以使用表里的字段,它們在讀表之前已經(jīng)準(zhǔn)備好了。以下的幾個例子中,MySQL使用了 eq_ref 連接來處理 ref_table

 

SELECT * FROM ref_table,other_tableWHERE ref_table.key_column=other_table.column;SELECT * FROM ref_table,other_tableWHERE ref_table.key_column_part1=other_table.columnAND ref_table.key_column_part2=1;

 

 

ref
該表中所有符合檢索值的記錄都會被取出來和從上一個表中取出來的記錄作聯(lián)合。ref 用于連接程序使用鍵的最左前綴或者是該鍵不是 PRIMARY KEYUNIQUE 索引(換句話說,就是連接程序無法根據(jù)鍵值只取得一條記錄)的情況。當(dāng)根據(jù)鍵值只查詢到少數(shù)幾條匹配的記錄時,這就是一個不錯的連接類型。ref 還可以用于檢索字段使用 = 操作符來比較的時候。以下的幾個例子中,MySQL將使用 ref 來處理 ref_table

 

SELECT * FROM ref_table WHERE key_column=expr;SELECT * FROM ref_table,other_tableWHERE ref_table.key_column=other_table.column;SELECT * FROM ref_table,other_tableWHERE ref_table.key_column_part1=other_table.columnAND ref_table.key_column_part2=1;

 

ref_or_null
這種連接類型類似 ref,不同的是MySQL會在檢索的時候額外的搜索包含 NULL 值的記錄。這種連接類型的優(yōu)化是從MySQL 4.1.1開始的,它經(jīng)常用于子查詢。在以下的例子中,MySQL使用 ref_or_null 類型來處理 ref_table

 

SELECT * FROM ref_tableWHERE key_column=expr OR key_column IS NULL;

詳情請看"7.2.6 How MySQL Optimizes IS NULL"。

 

index_merge
這種連接類型意味著使用了 Index Merge 優(yōu)化方法。這種情況下,key字段包括了所有使用的索引,key_len 包括了使用的鍵的最長部分。詳情請看"7.2.5 How MySQL Optimizes OR Clauses"。

 

 

unique_subquery
這種類型用例如一下形式的 IN 子查詢來替換 ref

 

value IN (SELECT primary_key FROM single_table WHERE some_expr)

unique_subquery 只是用來完全替換子查詢的索引查找函數(shù)效率更高了。

 

index_subquery
這種連接類型類似 unique_subquery。它用子查詢來代替 IN,不過它用于在子查詢中沒有唯一索引的情況下,例如以下形式:

 

value IN (SELECT key_column FROM single_table WHERE some_expr)

 

 

range
只有在給定范圍的記錄才會被取出來,利用索引來取得一條記錄。key 字段表示使用了哪個索引。key_len 字段包括了使用的鍵的最長部分。這種類型時 ref 字段值是 NULL。range 用于將某個字段和一個定植用以下任何操作符比較時 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, 或 IN

 

SELECT * FROM tbl_nameWHERE key_column = 10;SELECT * FROM tbl_nameWHERE key_column BETWEEN 10 and 20;SELECT * FROM tbl_nameWHERE key_column IN (10,20,30);SELECT * FROM tbl_nameWHERE key_part1= 10 AND key_part2 IN (10,20,30);

 

 

index
連接類型跟 ALL 一樣,不同的是它只掃描索引樹。它通常會比 ALL 快點,因為索引文件通常比數(shù)據(jù)文件小。MySQL在查詢的字段知識單獨的索引的一部分的情況下使用這種連接類型。

 

 

ALL
將對該表做全部掃描以和從前一個表中取得的記錄作聯(lián)合。這時候如果第一個表沒有被標(biāo)識為 const 的話就不大好了,在其他情況下通常是非常糟糕的。正常地,可以通過增加索引使得能從表中更快的取得記錄以避免 ALL

 

 

possible_keys
possible_keys 字段是指MySQL在搜索表記錄時可能使用哪個索引。注意,這個字段完全獨立于 EXPLAIN 顯示的表順序。這就意味著 possible_keys 里面所包含的索引可能在實際的使用中沒用到。如果這個字段的值是 NULL,就表示沒有索引被用到。這種情況下,就可以檢查 WHERE 子句中哪些字段那些字段適合增加索引以提高查詢的性能。就這樣,創(chuàng)建一下索引,然后再用 EXPLAIN 檢查一下。詳細(xì)的查看章節(jié)"14.2.2 ALTER TABLE Syntax"。想看表都有什么索引,可以通過 SHOW INDEX FROM tbl_name 來看。

 

 

 

key
key 字段顯示了MySQL實際上要用的索引。當(dāng)沒有任何索引被用到的時候,這個字段的值就是 NULL。想要讓MySQL強(qiáng)行使用或者忽略在 possible_keys 字段中的索引列表,可以在查詢語句中使用關(guān)鍵字FORCE INDEX, USE INDEX, 或 IGNORE INDEX。如果是 MyISAMBDB 類型表,可以使用 ANALYZE TABLE 來幫助分析使用使用哪個索引更好。如果是 MyISAM 類型表,運行命令 myisamchk --analyze 也是一樣的效果。詳細(xì)的可以查看章節(jié)"14.5.2.1 ANALYZE TABLE Syntax"和"5.7.2 Table Maintenance and Crash Recovery"。

 

 

key_len
key_len 字段顯示了MySQL使用索引的長度。當(dāng) key 字段的值為 NULL 時,索引的長度就是 NULL。注意,key_len 的值可以告訴你在聯(lián)合索引中MySQL會真正使用了哪些索引。

 

 

ref
ref 字段顯示了哪些字段或者常量被用來和 key 配合從表中查詢記錄出來。

 

 

rows
rows 字段顯示了MySQL認(rèn)為在查詢中應(yīng)該檢索的記錄數(shù)。

 

 

Extra
本字段顯示了查詢中MySQL的附加信息。以下是這個字段的幾個不同值的解釋:

 

 

Distinct
MySQL當(dāng)找到當(dāng)前記錄的匹配聯(lián)合結(jié)果的第一條記錄之后,就不再搜索其他記錄了。

 

 

Not exists
MySQL在查詢時做一個 LEFT JOIN 優(yōu)化時,當(dāng)它在當(dāng)前表中找到了和前一條記錄符合 LEFT JOIN 條件后,就不再搜索更多的記錄了。下面是一個這種類型的查詢例子:

 

SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.idWHERE t2.id IS NULL;

假使 t2.id 定義為 NOT NULL。這種情況下,MySQL將會掃描表 t1 并且用 t1.id 的值在 t2 中查找記錄。當(dāng)在 t2 中找到一條匹配的記錄時,這就意味著 t2.id 肯定不會都是 NULL,就不會再在 t2 中查找相同 id 值的其他記錄了。也可以這么說,對于 t1 中的每個記錄,MySQL只需要在 t2 中做一次查找,而不管在 t2 中實際有多少匹配的記錄。

 

range checked for each record (index map: #)
MySQL沒找到合適的可用的索引。取代的辦法是,對于前一個表的每一個行連接,它會做一個檢驗以決定該使用哪個索引(如果有的話),并且使用這個索引來從表里取得記錄。這個過程不會很快,但總比沒有任何索引時做表連接來得快。

 

 

Using filesort
MySQL需要額外的做一遍從而以排好的順序取得記錄。排序程序根據(jù)連接的類型遍歷所有的記錄,并且將所有符合 WHERE 條件的記錄的要排序的鍵和指向記錄的指針存儲起來。這些鍵已經(jīng)排完序了,對應(yīng)的記錄也會按照排好的順序取出來。詳情請看"7.2.9 How MySQL Optimizes ORDER BY"。

 

 

Using index
字段的信息直接從索引樹中的信息取得,而不再去掃描實際的記錄。這種策略用于查詢時的字段是一個獨立索引的一部分。

 

 

Using temporary
MySQL需要創(chuàng)建臨時表存儲結(jié)果以完成查詢。這種情況通常發(fā)生在查詢時包含了GROUP BYORDER BY 子句,它以不同的方式列出了各個字段。

 

 

Using where
WHERE 子句將用來限制哪些記錄匹配了下一個表或者發(fā)送給客戶端。除非你特別地想要取得或者檢查表種的所有記錄,否則的話當(dāng)查詢的 Extra 字段值不是 Using where 并且表連接類型是 ALLindex 時可能表示有問題。

如果你想要讓查詢盡可能的快,那么就應(yīng)該注意 Extra 字段的值為Using filesortUsing temporary 的情況。

 

你可以通過 EXPLAIN 的結(jié)果中 rows 字段的值的乘積大概地知道本次連接表現(xiàn)如何。它可以粗略地告訴我們MySQL在查詢過程中會查詢多少條記錄。如果是使用系統(tǒng)變量 max_join_size 來取得查詢結(jié)果,這個乘積還可以用來確定會執(zhí)行哪些多表 SELECT 語句。詳情請看"7.5.2 Tuning Server Parameters"。

下面的例子展示了如何通過 EXPLAIN 提供的信息來較大程度地優(yōu)化多表聯(lián)合查詢的性能。

假設(shè)有下面的 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.CUSTNAMEFROM tt, et, et AS et_1, doWHERE tt.SubmitTime IS NULLAND tt.ActualPC = et.EMPLOYIDAND tt.AssignedPC = et_1.EMPLOYIDAND tt.ClientID = do.CUSTNMBR;

在這個例子中,先做以下假設(shè):


  • 要比較的字段定義如下:
    Table Column Column Type
    tt ActualPC CHAR(10)
    tt AssignedPC CHAR(10)
    tt ClientID CHAR(10)
    et EMPLOYID CHAR(15)
    do CUSTNMBR CHAR(15)
  • 數(shù)據(jù)表的索引如下:
    Table Index
    tt ActualPC
    tt AssignedPC
    tt ClientID
    et EMPLOYID (primary key)
    do CUSTNMBR (primary key)
  • tt.ActualPC 的值是不均勻分布的。


在任何優(yōu)化措施未采取之前,經(jīng)過 EXPLAIN 分析的結(jié)果顯示如下:

 

table type possible_keys key  key_len ref  rows  Extraet    ALL  PRIMARY       NULL NULL    NULL 74do    ALL  PRIMARY       NULL NULL    NULL 2135et_1  ALL  PRIMARY       NULL NULL    NULL 74tt    ALL  AssignedPC,   NULL NULL    NULL 3872ClientID,ActualPCrange checked for each record (key map: 35)

由于字段 type 的對于每個表值都是 ALL,這個結(jié)果意味著MySQL對所有的表做一個迪卡爾積;這就是說,每條記錄的組合。這將需要花很長的時間,因為需要掃描每個表總記錄數(shù)乘積的總和。在這情況下,它的積是 74 * 2135 * 74 * 3872 = 45,268,558,720 條記錄。如果數(shù)據(jù)表更大的話,你可以想象一下需要多長的時間。

在這里有個問題是當(dāng)字段定義一樣的時候,MySQL就可以在這些字段上更快的是用索引(對 ISAM 類型的表來說,除非字段定義完全一樣,否則不會使用索引)。在這個前提下,VARCHARCHAR是一樣的除非它們定義的長度不一致。由于 tt.ActualPC 定義為 CHAR(10),et.EMPLOYID 定義為 CHAR(15),二者長度不一致。
為了解決這個問題,需要用 ALTER TABLE 來加大 ActualPC 的長度從10到15個字符:

mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);

現(xiàn)在 tt.ActualPCet.EMPLOYID 都是 VARCHAR(15)
了。再來執(zhí)行一次 EXPLAIN 語句看看結(jié)果:

table type   possible_keys key     key_len ref         rows    Extratt    ALL    AssignedPC,   NULL    NULL    NULL        3872    UsingClientID,                                         whereActualPCdo    ALL    PRIMARY       NULL    NULL    NULL        2135range checked for each record (key map: 1)et_1  ALL    PRIMARY       NULL    NULL    NULL        74range checked for each record (key map: 1)et    eq_ref PRIMARY       PRIMARY 15      tt.ActualPC 1

這還不夠,它還可以做的更好:現(xiàn)在 rows 值乘積已經(jīng)少了74倍。這次查詢需要用2秒鐘。
第二個改變是消除在比較 tt.AssignedPC = et_1.EMPLOYIDtt.ClientID = do.CUSTNMBR 中字段的長度不一致問題:

mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),->                MODIFY ClientID   VARCHAR(15);

現(xiàn)在 EXPLAIN 的結(jié)果如下:

table type   possible_keys key      key_len ref           rows Extraet    ALL    PRIMARY       NULL     NULL    NULL          74tt    ref    AssignedPC,   ActualPC 15      et.EMPLOYID   52   UsingClientID,                                         whereActualPCet_1  eq_ref PRIMARY       PRIMARY  15      tt.AssignedPC 1do    eq_ref PRIMARY       PRIMARY  15      tt.ClientID   1

這看起來已經(jīng)是能做的最好的結(jié)果了。
遺留下來的問題是,MySQL默認(rèn)地認(rèn)為字段tt.ActualPC 的值是均勻分布的,然而表 tt 并非如此。幸好,我們可以很方便的讓MySQL分析索引的分布:

mysql> ANALYZE TABLE tt;

到此為止,表連接已經(jīng)優(yōu)化的很完美了,EXPLAIN 的結(jié)果如下:

table type   possible_keys key     key_len ref           rows Extratt    ALL    AssignedPC    NULL    NULL    NULL          3872 UsingClientID,                                        whereActualPCet    eq_ref PRIMARY       PRIMARY 15      tt.ActualPC   1et_1  eq_ref PRIMARY       PRIMARY 15      tt.AssignedPC 1do    eq_ref PRIMARY       PRIMARY 15      tt.ClientID   1

請注意,EXPLAIN 結(jié)果中的 rows 字段的值也是MySQL的連接優(yōu)化程序大致猜測的,請檢查這個值跟真實值是否基本一致。如果不是,可以通過在 SELECT 語句中使用 STRAIGHT_JOIN 來取得更好的性能,同時可以試著在 FROM
分句中用不同的次序列出各個表。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
MYSQL語句調(diào)優(yōu):MYSQL Explain 執(zhí)行計劃輸出詳解
MySQL數(shù)據(jù)庫Query的優(yōu)化
添加mysql索引的3條原則
我的MYSQL學(xué)習(xí)心得(十六) 優(yōu)化
神奇的 SQL 之 MySQL 執(zhí)行計劃 → EXPLAIN,讓我們了解 SQL 的執(zhí)行過程!
如何定位及優(yōu)化SQL語句的性能問題?看這篇就完了
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服