2016-02-19 57 views
0

的MySQL版本14.14 DISTRIB 58年5月1日,使用readline的5.1如何避免 「使用索引;使用臨時;使用的filesort」 在MySQL中,21表連接

紅帽Linux的GNU的(x86_64的)我接手一箇舊項目。我被要求加快速度。我通過啓用慢查詢日誌。我正在檢查慢查詢日誌中出現的查詢。該查詢需要10秒鐘才能運行,並返回11,000行。

select 
    substring_index(ob1.literal,'/',1) AS sku4, 
    substring_index(
    substring_index(ob1.literal,'/',2),'/',-(1)) AS sku5, 
    substring_index(
    substring_index(ob1.literal,'/',3),'/',-(1)) AS sku6, 
    substring_index(ob2.literal,'/',1) AS sku7, 
    substring_index(
    substring_index(ob2.literal,'/',2),'/',-(1)) AS sku8, 
    substring_index(
    substring_index(ob2.literal,'/',3),'/',-(1)) AS sku9,concat_ws(',',ob.level_one, 
    substring_index(ob1.literal,'/',1), 
    substring_index(ob2.literal,'/',1)) AS sku1_filter,concat_ws(',',ob.level_two, 
    substring_index(
    substring_index(ob1.literal,'/',2),'/',-(1)), 
    substring_index(
    substring_index(ob2.literal,'/',2),'/',-(1))) AS sku2_filter,concat_ws(',',ob.level_three, 
    substring_index(
    substring_index(ob1.literal,'/',3),'/',-(1)), 
    substring_index(
    substring_index(ob2.literal,'/',3),'/',-(1))) AS sku3_filter, 
    t.title_id AS title_id, 
    t.us_list_price AS us_list_price, 
    t.uk_list_price AS uk_list_price, 
    t.can_list_price AS can_list_price, 
    t.aus_list_price AS aus_list_price, 
    t.min_age AS min_age, 
    t.max_age AS max_age, 
    t.book_club AS book_club, 
    t.best_seller AS best_seller, 
    t.award_winner AS award_winner, 
    t.asin AS asin, 
    t.format AS format, 
    ob.literal AS literal_1, 
    ob1.literal AS literal_2, 
    ob2.literal AS literal_3, 
    t.series AS series, 
    t.volume AS volume, 
    group_concat(distinct concat(u.first_name, ' ', u.last_name) separator ', ') AS marketer, 
    a.group_letter AS group_letter, 
    group_concat(distinct concat(u2.first_name, ' ', u2.last_name) separator ', ') AS editor, 
    oi.imprint_name AS imprint_name, 
    ob.level_one AS level_one, 
    ob.level_two AS level_two, 
    ob.level_three AS level_three, 
    ot1.territory_name AS rights, 
    (case when (isnull(t.active) or (t.active = '')) 
      then '' when (t.active = 'Y') 
      then 'Active' when (t.active = 'N') 
      then 'In Development' when (t.active = 'X') 
      then 'Terminated' when (t.active = 'T') 
      then 'Transmittal' end) AS status, 
    (case when (isnull(t.format) or (t.format = '')) 
      then '' when (t.format = 4) 
      then 'Ebook' when (t.format = 8) 
      then 'Print Book' when (t.format = 9) 
      then 'Audio Book' end) AS format_name, 
    t.title AS title,t.primary_isbn13 AS primary_isbn13, 
    group_concat(distinct a.display_name order by a.display_name ASC separator ', ') AS contributors, 
    group_concat(distinct c1.display_name order by c1.display_name ASC separator ', ') AS publishers, 
    t.publish_date AS pub_date, 
    group_concat(distinct g.name order by g.name ASC separator ', ') AS category, 
    group_concat(distinct g0.id order by g0.id ASC separator ', ') AS secondary_category_ids, 
    group_concat(distinct g0.name order by g0.name ASC separator ', ') AS secondary_categories 
    from ((((((((((((((((((((wawa_title t 
     left join wawa_title_to_imprint tti on((t.title_id = tti.title_id))) 
     left join wawa_imprint oi on((tti.imprint_id = oi.imprint_id))) 
     left join wawa_title_to_supplier t2a on((t2a.title_id = t.title_id))) 
     left join wawa_territories ot1 on((t.territory_id = ot1.territory_id))) 
     left join wawa_supplier a on((a.supplier_id = t2a.supplier_id))) 
     left join wawa_sku ob on((ob.code = t.sku1))) 
     left join wawa_sku ob1 on((ob1.code = t.sku2))) 
     left join wawa_sku ob2 on((ob2.code = t.sku3))) 
     left join bll_formats tf on((t.format = tf.id))) 
     left join bll_suppliers_to_wawa_editors aoe on((a.supplier_id = aoe.supplier_id))) 
     left join bll_suppliers_to_wawa_marketing_contacts amc on((a.supplier_id = amc.supplier_id))) 
     left join bll_contacts c0 on((c0.id = amc.id))) 
     left join users u on((amc.user_id = u.id))) 
     left join users u2 on((aoe.user_id = u2.id))) 
     join wawa_title_to_publisher t2p on((t2p.title_id = t.title_id))) 
     join wawa_publisher p on((p.publisher_id = t2p.publisher_id))) 
     join bll_contacts c1 on((c1.id = p.org_contact_id))) 
     left join wawa_title_to_genre t2g on((t2g.title_id = t.title_id))) 
     left join wawa_genres g on((g.id = t2g.genre_id_2))) 
     left join wawa_genres g0 on((g0.id = t2g.genre_id_3))) where ((t.title_id = t.title_id) and (t.active <> 'X')) 
    group by t.title_id 

EXPLAIN的輸出是:

+----+-------------+-------+--------+-----------------------------------------------------------------------------------------------+-------------------------------------+---------+------------------------------------------+------+----------------------------------------------+ 
    | id | select_type | table | type | possible_keys                     | key         | key_len | ref          | rows | Extra          | 
    +----+-------------+-------+--------+-----------------------------------------------------------------------------------------------+-------------------------------------+---------+------------------------------------------+------+----------------------------------------------+ 
    | 1 | SIMPLE  | p  | index | PRIMARY,org_contact_fk                  | org_contact_fk      | 5  | NULL          | 66 | Using index; Using temporary; Using filesort | 
    | 1 | SIMPLE  | c1 | eq_ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.p.org_contact_id | 1 |            | 
    | 1 | SIMPLE  | t2p | ref | idx_title_id,idx_publisher_id                 | idx_publisher_id     | 4  | wawa_ripple_development.p.publisher_id | 66 | Using where         | 
    | 1 | SIMPLE  | t  | eq_ref | PRIMARY,active_index,idx_title_active_isprimary            | PRIMARY        | 4  | wawa_ripple_development.t2p.title_id  | 1 | Using where         | 
    | 1 | SIMPLE  | t2g | ref | idx_title_id                     | idx_title_id      | 4  | wawa_ripple_development.t2p.title_id  | 1 |            | 
    | 1 | SIMPLE  | g  | eq_ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.t2g.genre_id_2 | 1 |            | 
    | 1 | SIMPLE  | g0 | eq_ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.t2g.genre_id_3 | 1 |            | 
    | 1 | SIMPLE  | tti | ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.t.title_id  | 1 | Using index         | 
    | 1 | SIMPLE  | oi | eq_ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.tti.imprint_id | 1 |            | 
    | 1 | SIMPLE  | t2a | ref | title_id                      | title_id       | 4  | wawa_ripple_development.t.title_id  | 1 | Using index         | 
    | 1 | SIMPLE  | ot1 | eq_ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.t.territory_id | 1 |            | 
    | 1 | SIMPLE  | a  | eq_ref | PRIMARY,wawa_supplier_venue_id_supplier_id              | PRIMARY        | 4  | wawa_ripple_development.t2a.supplier_id | 1 |            | 
    | 1 | SIMPLE  | ob | eq_ref | PRIMARY                      | PRIMARY        | 29  | wawa_ripple_development.t.sku1   | 1 |            | 
    | 1 | SIMPLE  | ob1 | eq_ref | PRIMARY                      | PRIMARY        | 29  | wawa_ripple_development.t.sku2   | 1 |            | 
    | 1 | SIMPLE  | ob2 | eq_ref | PRIMARY                      | PRIMARY        | 29  | wawa_ripple_development.t.sku3   | 1 |            | 
    | 1 | SIMPLE  | tf | eq_ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.t.format   | 1 | Using index         | 
    | 1 | SIMPLE  | aoe | ref | idx_by_supplier_and_editor,index_bll_suppliers_to_wawa_editors_on_supplier_id      | idx_by_supplier_and_editor   | 4  | wawa_ripple_development.a.supplier_id  | 1 | Using index         | 
    | 1 | SIMPLE  | amc | ref | idx_by_supplier_and_marketing_contact,index_bll_suppliers_to_wawa_marketing_contacts_on_supplier_id | idx_by_supplier_and_marketing_contact | 4  | wawa_ripple_development.a.supplier_id  | 1 | Using index         | 
    | 1 | SIMPLE  | c0 | eq_ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.amc.id   | 1 | Using index         | 
    | 1 | SIMPLE  | u  | eq_ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.amc.user_id  | 1 |            | 
    | 1 | SIMPLE  | u2 | eq_ref | PRIMARY                      | PRIMARY        | 4  | wawa_ripple_development.aoe.user_id  | 1 |            | 
    +----+-------------+-------+--------+-----------------------------------------------------------------------------------------------+-------------------------------------+---------+------------------------------------------+------+----------------------------------------------+ 

我擔心兩件事情:

1)使用索引;使用臨時;使用文件排序

2)使用其中

我說得對不對在意這些?

對於我能做些什麼來加快速度的建議?

一些變量:

mysql> show variables like '%buffer%'; 
    +-------------------------+---------+ 
    | Variable_name   | Value | 
    +-------------------------+---------+ 
    | bulk_insert_buffer_size | 8388608 | 
    | innodb_buffer_pool_size | 8388608 | 
    | innodb_log_buffer_size | 1048576 | 
    | join_buffer_size  | 131072 | 
    | key_buffer_size   | 8384512 | 
    | myisam_sort_buffer_size | 8388608 | 
    | net_buffer_length  | 16384 | 
    | preload_buffer_size  | 32768 | 
    | read_buffer_size  | 131072 | 
    | read_rnd_buffer_size | 262144 | 
    | sort_buffer_size  | 2097144 | 
    | sql_buffer_result  | OFF  | 
    +-------------------------+---------+ 

回答

1
  • 使用指數(也輸入=指數) - 這是一個 '好' 的東西。它表示,該表的工作完全可以在索引的BTree中完成,而不會觸及數據。
  • 使用臨時 - 這說至少有一個臨時表是執行查詢所需的。有查詢絕對必須有一個tmp表。所以和它一起生活吧。注意:這個短語在EXPLAIN中的位置並不表示哪個表真的需要tmp或filesort。有關詳細信息,請參閱EXPLAIN FORMAT=JSON SELECT ...
  • 使用filesort - 這說至少有一個步驟需要排序。它確實而不是說這種排序是否必須擊中磁盤。再次,這可能是絕對必要的。
  • 使用where - 並不意味着什麼
  • 使用索引條件 - 這與「使用索引」不同。 ICP意味着複雜的WHERE有一定的效率;這隻適用於較新的版本。
  • eq_ref - 下表中的一行是所需的。好。
  • 裁判 - 而不是1:1,但1:很多。從EXPLAIN,它似乎經常接近1:1。

至於加速起來......

  • 你需要LEFT?如果沒有擺脫它;優化器可能更喜歡某些其他順序的表。
  • EXPLAIN說,沒有多少行需要的是牽強。 (注意:請解釋的「行」數字是近似的)所以,我這裏看不到太大的幫助。
  • 看看你能不能讓「覆蓋索引」對於一些JOINs的 - 但僅限於「裁判」的情況下做到這一點,而不是「eq_ref +主」的情況。看起來你已經完成了這個徹底的工作。
  • 你將如何處理11000行?這對UI來說似乎是「不合理的」?如果它註定要進一步處理,那麼它多久執行一次? (也就是說,10秒真的很重要嗎?)
  • 你用什麼引擎?你有多少RAM? SHOW VARIABLES LIKE '%buffer%'; - 我正在釣魚memory utilization
  • JOIN + GROUP BY - 這通常意味着爆炸的行,然後是內爆。更改部分JOIN以子查詢中SELECT可能改善東西:(SELECT ... FROM ... WHERE ... LIMIT 1) AS whatever
  • 是否有任何字段TEXT?這迫使「filesort」內存不足(因此,速度較慢)。給我更多的細節,也許我們可以解決它。

總之,EXPLAIN看起來很乾淨。 JOINs的數量巨大是另一回事。

兩個潛在壞架構設計:跨表(* _price)跨列

  • 陣列

    • 陣列(水平*,SKU *,用戶*,流派*)

    Addenda

    對於16GB的RAM以及InnoDB和MyISAM的混合,建議使用key_buffer_size = 1500Minnodb_buffer_pool_size = 5G。將其設置爲my.cnf(或my.ini),然後重新啓動mysqld

  • +0

    謝謝。該服務器有16個RAM的演出。這些引擎是InnoDB和MySAMI的混淆組合。 – lorm

    +0

    我向主帖添加了可變數據。 – lorm

    +0

    我添加了最重要的設置 - 您擁有的設置非常低,並且是性能問題的一部分。 –

    相關問題