2010-07-26 58 views
3

我有一個表1和表2MySQL的性能,內聯接,如何避免使用臨時和文件排序

表1 PARTNUM - ID_BRAND partnum是主鍵 id_brand爲「索引」

表2 ID_BRAND - BRAND_NAME id_brand是主鍵 BRAND_NAME爲 「索引」

表1包含百萬的記錄和表2含有1.000記錄。

我試圖優化一些查詢使用EXPLAIN和經過很多嘗試後,我已經到了死衚衕。

EXPLAIN 
SELECT pm.partnum, pb.brand_name 
FROM products_main AS pm 
LEFT JOIN products_brands AS pb ON pm.id_brand=pb.id_brand 
ORDER BY pb.brand ASC 
LIMIT 0, 10 

查詢返回該執行計劃:

ID, SELECT_TYPE, TABLE, TYPE, POSSIBLE_KEYS, KEY, KEY_LEN , REF, ROWS, EXTRA 
1, SIMPLE, pm, range, PRIMARY, PRIMARY, 1, , 1000000, Using where; Using temporary; Using filesort 
1, SIMPLE, pb, ref, PRIMARY, PRIMARY, 4, demo.pm.id_pbrand, 1, 

MySQL查詢優化器顯示在執行計劃中暫時+文件排序。 我怎樣才能避免這種情況?

「EVIL」位於ORDER BY pb.brand ASC。通過該外部訂單排序似乎是瓶頸..

+0

你在這張表裏有什麼指標? – eillarra 2010-07-26 13:31:27

+0

根據猜測,除非您有pb.brand上的索引,否則mysql將需要在應用限制之前對所有1M行進行排序 – StuartLC 2010-07-26 13:44:50

+0

表1:PARTNUM是PK並且ID_BRAND是加速的索引 表2:ID_BRAND是PK和BRAND是加速的指標 – Vincenzo 2010-07-26 13:53:25

回答

0

首先,嘗試更改您的索引products_brands表。刪除brand_name現有的一個,並創建一個新:

ALTER TABLE products_brands ADD INDEX newIdx (brand_name, id_brand) 

然後,該表將已經有你需要的加入ID的「orderedByBrandName」索引,你可以嘗試:

EXPLAIN 
SELECT pb.brand_name, pm.partnum 
FROM products_brands AS pb 
    LEFT JOIN products_main AS pm ON pb.id_brand = pm.id_brand 
LIMIT 0, 10 

請注意,我也改變了查詢中表格的順序,所以你從之一開始。

+0

我在PRODUCTS_BRANDS上有兩個索引。 第一個是id_brand(它是主鍵,它有一個隱式索引)。 brand_name上的第二個。 – Vincenzo 2010-07-26 15:27:39

+0

我已經改變了JOIN TABLES的順序,但沒有任何變化。 查詢優化器選擇表的順序,它不遵循SQL sintax的順序。 – Vincenzo 2010-07-26 15:29:45

+0

你是否改變了索引?我在您的問題中讀到您有兩個索引:您需要更改brand_name上的索引,並將其設置爲(brand_name,id_brand)。 – eillarra 2010-07-26 16:03:13

0

首先,我質疑外部連接的使用,因爲順序是通過對rhs進行操作的,而且由左連接注入的NULL可能會對它造成嚴重破壞。

無論如何,加速查詢的最簡單方法是在pb.id_brand和pb.brand上覆蓋索引。這將允許通過連接條件對「order index」進行評估。另一種方法是找到一些方法來減小傳遞給訂單的中間結果的大小。

儘管如此,outer-join,order-by和limit的組合還是讓我想知道你究竟在詢問什麼,以及是否沒有更好的表達查詢本身的方法。

1

嘗試用子查詢替換連接。 MySQL的優化器很糟糕;子查詢通常會比聯接提供更好的性能。

+0

你有這個......的來源嗎? – jocull 2011-06-29 15:44:10

+0

我測試了一個類似的查詢,他是對的,它造成了巨大的差異。將ORDER BY x DESC LIMIT 20移動到子查詢中,刪除了Using temporary,查詢時間從5秒延長到了0.0017秒。 – ColinM 2012-05-03 18:15:38

+5

@ColinM你如何將'ORDER BY x DESC LIMIT 20'移動到子查詢中?也許你可以發佈一個查詢例子作爲這個問題的附加答案? – 2013-05-05 12:01:32

0

這個問題有點過時了,但我確實找到了,其他人也會這樣。

如果ORDER BY或GROUP BY包含來自聯接隊列中第一個表以外的表的列,則Mysql使用臨時表。

所以,你只需要必須使用STRAIGHT_JOIN,繞過通過優化發明了本末倒置的連接順序:

SELECT STRAIGHT_JOIN pm.partnum, pb.brand_name 
FROM products_brands AS pb 
RIGHT JOIN products_main AS pm ON pm.id_brand=pb.id_brand 
ORDER BY pb.brand ASC 
LIMIT 0, 10 

還要確保max_heap_table_size和tmp_table_size的變量被設置爲一個數字足夠大的存儲結果:

SET global tmp_table_size=100000000; 
SET global max_heap_table_size=100000000; 

- 本例中爲100兆字節。這些也可以在my.cnf配置文件中設置。