簡體   English   中英

MySQL MyISAM表性能......痛苦,痛苦地緩慢

[英]MySQL MyISAM table performance… painfully, painfully slow

我有一個表結構,可以總結如下:

pagegroup
* pagegroupid
* name

有3600行

page
* pageid
* pagegroupid
* data

引用頁組; 有10000行; 每頁組可以有1-700行之間的任何內容; 數據列的類型為mediumtext,該列每行包含100k - 200kbytes數據

userdata
* userdataid
* pageid
* column1
* column2
* column9

參考頁面; 有大約300,000行; 每頁可以有大約1-50行

上面的結構是相當直接的轉發,問題是從userdata到頁面組的連接非常非常慢,即使我已經索引了應該被索引的所有列。 運行此類連接的查詢所需的時間(userdata inner_join page inner_join pagegroup)超過3分鍾。 考慮到我根本沒有選擇數據列這一事實,這非常慢。 查詢示例耗時太長:

SELECT userdata.column1, pagegroup.name
FROM userdata
INNER JOIN page USING( pageid )
INNER JOIN pagegroup USING( pagegroupid )

請幫助解釋為什么需要這么長時間,我該怎么做才能讓它更快。

編輯#1

在胡言亂語之后解釋回復:

id  select_type  table      type    possible_keys        key      key_len  ref                         rows    Extra
1   SIMPLE       userdata   ALL     pageid                                                             372420
1   SIMPLE       page       eq_ref  PRIMARY,pagegroupid  PRIMARY  4        topsecret.userdata.pageid   1
1   SIMPLE       pagegroup  eq_ref  PRIMARY              PRIMARY  4        topsecret.page.pagegroupid  1

編輯#2

SELECT
u.field2, p.pageid
FROM
userdata u
INNER JOIN page p ON u.pageid = p.pageid;
/*
0.07 sec execution, 6.05 sec fecth
*/

id  select_type  table  type    possible_keys  key      key_len  ref                rows     Extra
1   SIMPLE       u      ALL     pageid                                              372420
1   SIMPLE       p      eq_ref  PRIMARY        PRIMARY  4        topsecret.u.pageid 1        Using index

SELECT
p.pageid, g.pagegroupid
FROM
page p
INNER JOIN pagegroup g ON p.pagegroupid = g.pagegroupid;
/*
9.37 sec execution, 60.0 sec fetch
*/

id  select_type  table  type   possible_keys  key          key_len  ref                      rows  Extra
1   SIMPLE       g      index  PRIMARY        PRIMARY      4                                 3646  Using index
1   SIMPLE       p      ref    pagegroupid    pagegroupid  5        topsecret.g.pagegroupid  3     Using where

故事的道德啟示

如果遇到諸如此類的性能問題,請將中/長文本列保留在單獨的表中。

userdata表中columnX的數據類型和用途是什么? 應該注意的是,任何文本數據類型(即排除char,varchar)都會強制在磁盤上創建任何臨時表。 既然你在沒有條件,分組或排序的情況下進行直接連接,它可能不需要任何臨時表,除了聚合最終結果。

如果您向我們展示如何創建索引,我認為這也將非常有用。 需要記住的一點是,雖然InnoDB將表的主鍵連接到每個索引,但MyISAM卻沒有。 這意味着如果您索引列並使用LIKE搜索它,但仍希望獲取頁組的ID ; 然后查詢仍然需要訪問表來獲取id,而不是能夠從索引中檢索它。

這意味着,在您的情況下,如果我理解您對apphacker的正確評論,那就是獲取每個用戶頁面組的名稱。 查詢優化器希望使用索引進行連接,但是對於每個結果,它還需要訪問該表以檢索頁組名稱。 如果您的數據類型名稱不大於中等varchar,即沒有文本,您還可以創建一個索引(id,name),使索引能夠直接從索引中獲取名稱。

作為最后的嘗試,您指出如果mediumtext不在頁表中,整個查詢可能會更快。

  1. 從您正在運行的查詢中排除此列?
  2. 您還可以嘗試將頁面數據與頁面“配置”分開,即它屬於哪個組。 那你可能會有類似的東西:
    • 網頁
      • PAGEID
      • pageGroupId
    • PageData
      • PAGEID
      • 數據

這有望使您能夠更快地加入,因為Pages中的列沒有占用太多空間。 然后,當您需要顯示某個頁面時,您將使用pageId-column上的PageData表連接以獲取顯示特定頁面所需的數據。

找出MySQL對您的查詢執行的操作的簡單方法是讓它向您解釋查詢。 運行此命令並查看輸出:

EXPLAIN SELECT userdata.column1, pagegroup.name
FROM userdata
INNER JOIN page USING( pageid )
INNER JOIN pagegroup USING( pagegroupid )

MySQL將告訴您它處理查詢的順序以及它使用的索引。 您創建索引的事實並不意味着MySQL實際使用它們。

另請參閱使用EXPLAIN優化查詢

編輯

EXPLAIN的輸出看起來很好。 它在userdata表上執行全表掃描,但這是正常的,因為您要返回其中的所有行。 優化此方法的最佳方法是重新考慮您的應用程序。 你真的需要返回所有372K行嗎?

我假設userdata表非常大並且不適合內存。 MySQL必須從硬盤讀取整個表,即使它只需要兩個小列。

您可以嘗試通過定義包含查詢所需內容的索引來消除掃描整個表的需要。 這樣,索引不是一種方便搜索主表的方法,但它是表本身的簡寫版本。 MySQL只需要從磁盤讀取速記表。

索引可能如下所示:

column1, pageid

這必須是非群集的,否則它將成為大表的一部分,從而破壞其目的。 有關MySQL如何決定群集索引的想法,請參閱此頁面 最簡單的方法似乎是確保在pageid上有一個主鍵,它將被群集化,因此輔助column1 + pageid索引將是非群集的。

一個可能的問題是MySQL每個查詢只使用一個索引,也許你沒有這些列的單個索引 - 或者MySQL的查詢優化器沒有選擇它。 EXPLAIN SELECT &c在這里告訴你什么?

我會先打破查詢,弄清楚是否有一個慢速和一個快速部分,或者兩者都很慢(對不起,我不喜歡USING語法,所以我將使用ON):

SELECT 
  u.userdata, p.pageid
FROM
  userdata u
  INNER JOIN page p ON u.pageid = p.pageid

SELECT 
  p.pageid, g.pagegroupid
FROM
  page 
  INNER JOIN pagegroup g ON p.pagegroupid = g.pagegroupid

這給你帶來了什么? 使用EXPLAIN EXTENDED運行這些將提供額外的提示。

看起來你正在對userdata上的所有行進行連接,然后嘗試選擇所有內容。 這是每一個pagepagegroupuserdata WHERE子句在WHERE 沒有LIMIT ,你想要多少結果? 你為什么不得到你的行數倒在userdata在連續explain結果,應加快查詢。 嘿。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM