国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

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

MySQL優(yōu)化(二)

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

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

 

EXPLAIN tbl_name

或者:

EXPLAIN SELECT select_options

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

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

 

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

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

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

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

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

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

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

 

 

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

 

 

select_type
SELECT 的類型,可能會(huì)有以下幾種:

 

 

 

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

 

PRIMARY
最外層的 SELECT

 

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

 

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

 

SUBQUERY
子查詢中的第一個(gè) SELECT

 

DEPENDENT SUBQUERY
子查詢中的第一個(gè) SUBQUERY 依賴于外部的子查詢

 

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

 

 

table
記錄查詢引用的表。

 

 

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

 

 

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

 

 

const
表中最多只有一行匹配的記錄,它在查詢一開始的時(shí)候就會(huì)被讀取出來。由于只有一行記錄,在余下的優(yōu)化程序里該行記錄的字段值可以被當(dāng)作是一個(gè)恒定值。const 表查詢起來非???,因?yàn)橹灰x取一次!const 用于在和 PRIMARY KEYUNIQUE 索引中有固定值比較的情形。下面的幾個(gè)查詢中,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
從該表中會(huì)有一行記錄被讀取出來以和從前一個(gè)表中讀取出來的記錄做聯(lián)合。與 const 類型不同的是,這是最好的連接類型。它用在索引所有部分都用于做連接并且這個(gè)索引是一個(gè) PRIMARY KEYUNIQUE 類型。eq_ref 可以用于在進(jìn)行"="做比較時(shí)檢索字段。比較的值可以是固定值或者是表達(dá)式,表達(dá)示中可以使用表里的字段,它們?cè)谧x表之前已經(jīng)準(zhǔn)備好了。以下的幾個(gè)例子中,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
該表中所有符合檢索值的記錄都會(huì)被取出來和從上一個(gè)表中取出來的記錄作聯(lián)合。ref 用于連接程序使用鍵的最左前綴或者是該鍵不是 PRIMARY KEYUNIQUE 索引(換句話說,就是連接程序無法根據(jù)鍵值只取得一條記錄)的情況。當(dāng)根據(jù)鍵值只查詢到少數(shù)幾條匹配的記錄時(shí),這就是一個(gè)不錯(cuò)的連接類型。ref 還可以用于檢索字段使用 = 操作符來比較的時(shí)候。以下的幾個(gè)例子中,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會(huì)在檢索的時(shí)候額外的搜索包含 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;

詳情請(qǐng)看"7.2.6 How MySQL Optimizes IS NULL"。

 

index_merge
這種連接類型意味著使用了 Index Merge 優(yōu)化方法。這種情況下,key字段包括了所有使用的索引,key_len 包括了使用的鍵的最長(zhǎng)部分。詳情請(qǐng)看"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
只有在給定范圍的記錄才會(huì)被取出來,利用索引來取得一條記錄。key 字段表示使用了哪個(gè)索引。key_len 字段包括了使用的鍵的最長(zhǎng)部分。這種類型時(shí) ref 字段值是 NULL。range 用于將某個(gè)字段和一個(gè)定植用以下任何操作符比較時(shí) =, <>, >, >=, <, <=, 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 一樣,不同的是它只掃描索引樹。它通常會(huì)比 ALL 快點(diǎn),因?yàn)樗饕募ǔ1葦?shù)據(jù)文件小。MySQL在查詢的字段知識(shí)單獨(dú)的索引的一部分的情況下使用這種連接類型。

 

 

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

 

 

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

 

 

 

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

 

 

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

 

 

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

 

 

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

 

 

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

 

 

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

 

 

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

 

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

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

 

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

 

 

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

 

 

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

 

 

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

 

 

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

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

 

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

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

假設(shè)有下面的 SELECT 語句,正打算用 EXPLAIN 來檢測(cè):

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;

在這個(gè)例子中,先做以下假設(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 的對(duì)于每個(gè)表值都是 ALL,這個(gè)結(jié)果意味著MySQL對(duì)所有的表做一個(gè)迪卡爾積;這就是說,每條記錄的組合。這將需要花很長(zhǎng)的時(shí)間,因?yàn)樾枰獟呙杳總€(gè)表總記錄數(shù)乘積的總和。在這情況下,它的積是 74 * 2135 * 74 * 3872 = 45,268,558,720 條記錄。如果數(shù)據(jù)表更大的話,你可以想象一下需要多長(zhǎng)的時(shí)間。

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

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秒鐘。
第二個(gè)改變是消除在比較 tt.AssignedPC = et_1.EMPLOYIDtt.ClientID = do.CUSTNMBR 中字段的長(zhǎng)度不一致問題:

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

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

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

聯(lián)系客服