2010-09-22 85 views
0

我遇到了MySQL的奇怪行爲。 查詢執行(即explain [QUERY]所示的索引使用)和執行所需的時間取決於where子句的元素。爲什麼SELECT語句會影響MySQL中的查詢執行和性能?

這裏是哪裏出現問題的查詢:

select distinct 
e1.idx, el1.idx, r1.fk_cat, r2.fk_cat 
from ent e1, ent_leng el1, rel_c r1, _tax_c t1, rel_c r2, _tax_c t2 
where el1.fk_ent=e1.idx 
and r1.fk_ent=e1.idx and ((r1.fk_cat=43) or (r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43)) 
and r2.fk_ent=e1.idx and ((r2.fk_cat=10) or (r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10)) 

相應的解釋輸出:

| id | select_type | table | type | possible_keys   | key  | key_len | ref   | rows | Extra      
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------ 
| 1 | SIMPLE  | el1 | index | fk_ent     | fk_ent | 4  | NULL   | 15002 | Using index; Using temporary 
| 1 | SIMPLE  | e1 | eq_ref | PRIMARY     | PRIMARY | 4  | DB.el1.fk_ent |  1 | Using index 
| 1 | SIMPLE  | r1 | ref | fk_ent,fk_cat,fks  | fks  | 4  | DB.e1.idx  |  1 | Using where; Using index 
| 1 | SIMPLE  | r2 | ref | fk_ent,fk_cat,fks  | fks  | 4  | DB.el1.fk_ent |  1 | Using index 
| 1 | SIMPLE  | t1 | index | fk_cat1,fk_cat2,fk_cats | fk_cats | 8  | NULL   | 69 | Using where; Using index; Distinct; 
| |    |  |  |       |   |   |    |  | Using join buffer 
| 1 | SIMPLE  | t2 | index | fk_cat1,fk_cat2,fk_cats | fk_cats | 8  | NULL   | 69 | Using where; Using index; Distinct; 
                              | Using join buffer 

正如你可以看到一列的索引具有相同的名稱列它屬於。我還添加了一些無用的索引以及使用的索引,只是爲了看看它們是否改變了執行(它們不執行)。

執行需要4.5秒。

當我列entl1.name添加到選擇部分(沒有別的改變),在EL1指數fk_ent不能使用任何更多:

| id | select_type | table | type | possible_keys   | key  | key_len | ref   | rows | Extra      
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------ 
| 1 | SIMPLE  | el1 | ALL | fk_ent     | NULL | NULL | NULL   | 15002 | Using temporary 

執行現在只需〜8.5秒。

我一直認爲查詢的select部分不會影響引擎的索引使用,也不會以這種方式影響性能。

退出該屬性不是一個解決方案,並且還有更多的屬性需要我選擇。 更糟糕的是,用過的表單中的查詢甚至更復雜一些,這使得性能問題成爲一個大問題。

所以我的問題是: 1)這種奇怪的行爲是什麼原因? 2)如何解決性能問題?

感謝您的幫助! Gred

回答

2

這是DISTINCT限制。您可以將其視爲另一個WHERE限制。當您更改選擇列表時,您確實正在爲DISTINCT限制更改WHERE子句,現在優化器決定必須執行表掃描,因此它可能不會使用您的索引。

編輯:

不知道這是否有幫助,但如果我理解正確的數據,我想你可以擺脫DISTINCT限制這樣的:

select 
e1.idx, el1.idx, r1.fk_cat, r2.fk_cat 
from ent e1 
    Inner Join ent_leng el1 ON el1.fk_ent=e1.idx 
    Inner Join rel_c r1 ON r1.fk_ent=e1.idx 
    Inner Join rel_c r2 ON r2.fk_ent=e1.idx 
where 
((r1.fk_cat=43) or Exists(Select 1 From _tax_c t1 Where r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43)) 
and 
((r2.fk_cat=10) or Exists(Select 1 From _tax_c t2 Where r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10)) 
+0

聽起來很合理。但是這不是問題的解決方案(我不得不處理一個巨大的,準冗餘的結果集或使用複雜的索引)。而奇怪的是,刪除DISTINCT並不會改變EXPLAIN輸出,也不會加快查詢速度,因爲我剛剛檢查過。 – GredPapp 2010-09-22 15:34:58

+0

剛剛測試過:您的查詢似乎與我的結果相同 - 而且速度更快!謝謝!我想我必須更深入地瞭解SQL以適當地使用它。 – GredPapp 2010-09-22 18:33:58

0

MySQL將返回如果可能的話,從索引中獲取數據,保存整個行加載。這樣,選定的列可以影響索引選擇。

考慮到這一點,將所有必需的列添加到索引可以更加高效,特別是在僅選擇一小部分列的情況下。