乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      MySQL優(yōu)化(二) MySQL 卓越資源...

       昵稱90415 2009-02-25

      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 的同義詞來用,也可以用來獲取一個(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會解釋了即將如何運(yùn)行該 SELECT 語句,它顯示了表如何連接、連接的順序等信息。

       

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

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

      如果由于不恰當(dāng)使用索引而引起一些問題的話,可以運(yùn)行 ANALYZE TABLE 來更新該表的統(tǒng)計(jì)信息,例如鍵的基數(shù),它能幫您在優(yōu)化方面做出更好的選擇。詳情請看"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è)表中查找到對應(yīng)的記錄,然后在第三個(gè)表中查找,依次類推。當(dāng)所有的表都掃描完了,它輸出選擇的字段并且回溯所有的表,直到找不到為止,因?yàn)橛械谋碇锌赡苡卸鄺l匹配的記錄下一條記錄將從該表讀取,再從下一個(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)識符。在查詢中每個(gè) SELECT 都有一個(gè)順序的數(shù)值。

       

       

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

       

       

       

      SIMPLE
      簡單的 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í)候就會被讀取出來。由于只有一行記錄,在余下的優(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_name
      WHERE primary_key_part1=1 AND primary_key_part2=2;

       

       

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

       

      SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column=other_table.column;
      SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column_part1=other_table.column
      AND ref_table.key_column_part2=1;

       

       

      ref
      該表中所有符合檢索值的記錄都會被取出來和從上一個(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_table
      WHERE ref_table.key_column=other_table.column;
      SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column_part1=other_table.column
      AND ref_table.key_column_part2=1;

       

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

       

      SELECT * FROM ref_table
      WHERE 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 字段表示使用了哪個(gè)索引。key_len 字段包括了使用的鍵的最長部分。這種類型時(shí) ref 字段值是 NULLrange 用于將某個(gè)字段和一個(gè)定植用以下任何操作符比較時(shí) =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, 或 IN

       

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

       

       

      index
      連接類型跟 ALL 一樣,不同的是它只掃描索引樹。它通常會比 ALL 快點(diǎn),因?yàn)樗饕募ǔ1葦?shù)據(jù)文件小。MySQL在查詢的字段知識單獨(dú)的索引的一部分的情況下使用這種連接類型。

       

       

      ALL
      將對該表做全部掃描以和從前一個(gè)表中取得的記錄作聯(lián)合。這時(shí)候如果第一個(gè)表沒有被標(biāo)識為 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使用索引的長度。當(dāng) key 字段的值為 NULL 時(shí),索引的長度就是 NULL。注意,key_len 的值可以告訴你在聯(lián)合索引中MySQL會真正使用了哪些索引。

       

       

      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.id
      WHERE t2.id IS NULL;

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

       

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

       

       

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

       

       

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

       

       

      Using temporary
      MySQL需要創(chuàng)建臨時(shí)表存儲結(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在查詢過程中會查詢多少條記錄。如果是使用系統(tǒng)變量 max_join_size 來取得查詢結(jié)果,這個(gè)乘積還可以用來確定會執(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.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;

      在這個(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  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 (key map: 35)

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

      在這里有個(gè)問題是當(dāng)字段定義一樣的時(shí)候,MySQL就可以在這些字段上更快的是用索引(對 ISAM 類型的表來說,除非字段定義完全一樣,否則不會使用索引)。在這個(gè)前提下,VARCHARCHAR是一樣的除非它們定義的長度不一致。由于 tt.ActualPC 定義為 CHAR(10),et.EMPLOYID 定義為 CHAR(15),二者長度不一致。
      為了解決這個(gè)問題,需要用 ALTER TABLE 來加大 ActualPC 的長度從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    Extra
      tt    ALL    AssignedPC,   NULL    NULL    NULL        3872    Using
      ClientID,                                         where
      ActualPC
      do    ALL    PRIMARY       NULL    NULL    NULL        2135
      range checked for each record (key map: 1)
      et_1  ALL    PRIMARY       NULL    NULL    NULL        74
      range 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 中字段的長度不一致問題:

      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 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

      這看起來已經(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 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

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

        本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多