2017-10-18 99 views
0

這裏是一個醜陋的極端由我們的Web應用程序生成的查詢。這是一個自定義的Web應用程序,必須讀取舊版Wordpress數據庫。我需要寫什麼索引來防止在非高性能MySQL查詢中進行表分類?

SELECT SQL_NO_CACHE DISTINCT 
    p.ID, p.post_title, p.post_name, p.post_excerpt, p.post_date, p.post_date_gmt, p.comment_count, post_content, post_author 
FROM wp_posts p 
INNER JOIN wp_term_relationships AS tr ON p.ID = tr.object_id 
INNER JOIN wp_term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id 
INNER JOIN wp_terms AS t ON tt.term_id = t.term_id 
WHERE 
    tt.taxonomy = "post_tag" 
AND p.post_type = "post" 
AND p.post_password = '' 
AND p.post_status = "publish" 
ORDER BY p.post_date DESC 
LIMIT 0, 20 

爲了給你這個數據庫的大小的範圍:

  • wp_posts具有約250k行。
  • wp_term_relationship有約。 1m行。
  • wp_term_taxonomy有約。 50k行。
  • wp_terms有大約50k行。

這裏的EXPLAIN語句:

ID| SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS        | KEY    | KEY_LEN | REF      | ROWS | EXTRA 
1 | SIMPLE  | tt | ref | PRIMARY,term_id_taxonomy,taxonomy   | taxonomy   | 130  | const      | 27149 | Using index condition; Using temporary; Using filesort 
1 | SIMPLE  | t  | eq_ref | PRIMARY         | PRIMARY   | 8  | wp_mu.tt.term_id   | 1  | Using index 
1 | SIMPLE  | tr | ref | PRIMARY,term_taxonomy_id     | term_taxonomy_id | 8  | wp_mu.tt.term_taxonomy_id | 11 | Using index 
1 | SIMPLE  | p  | eq_ref | PRIMARY,type_status_date,optimize_slow_tax | PRIMARY   | 8  | wp_mu.tr.object_id  | 1  | Using where 

據我所知道的,主要問題是,MySQL是生成一個臨時表,並使用文件排序。

從我的閱讀到目前爲止,如果我能寫出正確的查詢,我們可以避免這整個崩潰。如果有必要創造一個母親巨大的指數,我準備這樣做。

我不是DBA,我不能輕鬆訪問一個,所以我需要幫助來根據這個查詢找出我應該寫的東西。

  • 我是否構建了此查詢中涉及的所有wp_posts列的索引?
  • 或者只是所有wp_posts列涉及WHERE子句?
  • 或者只是所有wp_posts列涉及WHERE和ORDER BY子句?如果是這樣,按什麼順序?
  • 或者只是所有wp_posts列涉及WHERE和ORDER BY和JOIN子句?如果是這樣,按什麼順序?
  • 以任何方式重新排序WHERE子句的順序,還是MySQL已經優化了這個?
  • 如果我要創建一個MySQL視圖,會有幫助嗎?我的閱讀暗示沒有,但是最近的MySQL版本最近可能表現更好?
+0

MySQL Views沒有幫助,因爲它們不是物化視圖。每次查詢視圖時,您都會逐字運行相同的查詢。所以視圖更像宏。正如Rick回答的,失去了「DISTINCT」。 –

+0

是的,我不這麼認爲。我想我可能希望MySQL 8.0有人認爲讓Views更高效,但也許MySQL用戶剛​​剛接受了使用它們的訓練。 – haz

+0

我很想切換到Postgresql以獲得物化視圖,但可悲的是,這不是我做出的決定,這意味着它永遠不會發生。 – haz

回答

1

「Filesort」並不像聽起來那麼邪惡。還有其他問題需要解決速度問題。他們可能會刪除文件。現在提供3個提示,其中每個提示可能都有幫助。

  1. wp_postmeta的多對多映射有幾個低效率。架構改進概述爲here。如果wp_term_taxonomy很多:很多,但不是wp_postmeta的克隆,那麼請參閱提示here

  2. 添加INDEX(post_type, post_password, post_status, post_date)p可能會有很大幫助。 (很難說沒有看到SHOW CREATE TABLE並知道有關數據分佈的一些信息。)列的順序可以是任意的,但post_date必須是最後一個。該索引可能會刪除'filesort'。但更重要的是,它可能會通過WHEREORDER BY以兌現LIMIT。沒有達到LIMIT,很多行必須收集,排序,最後LIMITed。這是涉及的行數,而不是文件夾,那就是小人。

  3. 哦,DISTINCT可能會強制tmp + filesort。這可以通過做

查詢的顯著重寫被淘汰:

SELECT ... 
    FROM posts AS p 
    WHERE p.... 
     AND EXISTS (SELECT * FROM .. JOIN .. JOIN .. 
         WHERE tt.taxonomy = "post_tag" 
         AND p.ID = tr.object_id) 
    ORDER BY ... 
    LIMIT ... 

注意如何除posts每個表已被移動到子查詢。之前,出現了「爆炸 - 爆裂」模式 - JOIN爆炸涉及的行數,然後GROUP BY(或DISTINCT)爆炸。這個表述避免了這種情況。

+0

我試過#2的各種變化,我似乎無法獲得增加很多價值的索引。另一方面 – haz

+0

#3是魔法。現在我只需要弄清楚如何重寫應用程序來重寫查詢。 – haz

+0

我在這個論壇上花費了很多精力,向人們展示瞭如何在SQL中提高效率,以便發現第三方軟件受到阻礙。 :('JOIN'可能會妨礙在#2中使用'INDEX',您能否提供'EXPLAIN SELECT ...'(在添加索引後);也許我可以找到一種解決方法。 –