2010-11-19 112 views
0

考慮以下兩個查詢:添加WHERE子句使查詢很慢

select a.*, c.* 
from account a 
join customer c on a.customer_id = c.id 
join import i on a.import_id = i.id 
join import_bundle ib on i.import_bundle_id = ib.id 

select a.*, c.* 
from account a 
join customer c on a.customer_id = c.id 
join import i on a.import_id = i.id 
join import_bundle ib on i.import_bundle_id = ib.id 
where ib.id = 8 

第一個查詢速度快,第二個是超級慢。任何想法爲什麼?我猜我需要一個索引或其他東西,但我不明白索引的工作原理。我正在使用MySQL。

這裏的,如果我在第二查詢做一個EXPLAIN會發生什麼:

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE ib const PRIMARY  PRIMARY  8 const 1 Using index 
1 SIMPLE c ALL  PRIMARY   144858 
1 SIMPLE a ref  fk_account_customer_id,fk_account_import_id  fk_account_customer_id 8 mcif.c.id 2 
1 SIMPLE i eq_ref PRIMARY,import_bundle_id PRIMARY  8 mcif.a.import_id 1 Using where 

我不知道如何解釋,雖然。

編輯:這是我最後使用:

select a.*, 
     c.* 
    from account a 
    join customer c on a.customer_id = c.id 
    join (select id, 
       import_bundle_id 
      from import 
     where import_bundle_id = 8) i on a.import_id = i.id 
    join import_bundle ib on i.import_bundle_id = ib.id 

import_bundle.id添加索引什麼也沒做。

+0

查詢計劃看起來像什麼?索引涵蓋ib.id? – 2010-11-19 19:46:08

+0

你是什麼意思,「查詢計劃看起來像什麼?」 – 2010-11-19 20:14:10

+0

有時,事情並不像他們看起來那樣。你如何比較這兩個查詢?你看過檢索_first_記錄的時間還是_last_記錄。後者是應該測量的東西,但如果您是從SQL客戶端應用程序開始工作,則只需查看前者即可。 – Axn 2010-11-19 20:20:39

回答

1
  • 關於性能,在您的查詢中,您確實需要a。*和c。*?

  • 因此,索引的使用不夠好。我不熟悉mysql,但你可以試試像這樣的子查詢連接?

 
    select a.*, c.* 
    from account a 
    join customer c on a.customer_id = c.id 
    join 
    ( 
     SELECT id, import_bundle_id FROM import WHERE id = 8 
    ) as i on a.import_id = i.id 
    join import_bundle ib on i.import_bundle_id = ib.id 
    where ib.id = 8 
  • 也許,最好的指標是:對import.import_bundle_id索引和import_bundle.id另一個指標。
+0

注意:爲了使它實際工作('where where id = 8'應該是'where import_bundle_id = 8'),我不得不編輯這個查詢,但子查詢的想法奏效了。該指數沒有改變任何東西。 – 2010-11-22 14:17:47

1

後者查詢強制MySQL發現結果與ib.id = 8

集如果添加一個索引來import_bundle.id內的結果,那麼MySQL將能夠快速找到相應的記錄,而不必全部檢查它們。

數據庫索引就像教科書中的索引,而不是查看每個頁面,然後轉到後面的索引,找到要查找的內容的頁碼並直接進入該索引。

+0

嗯,我做了'CREATE INDEX id_index ON import_bundle(id)',對速度沒有明顯的影響。我做錯了嗎? – 2010-11-19 19:55:06

+0

@Jason Swett不一定,該指數有望加速限制結果集的過程,但仍需要一些時間。 – Orbling 2010-11-19 20:15:16

+0

@Jason Swett我從你的查詢計劃中看到,import_bundle.id已經是該表的主鍵了嗎?主鍵本身就是一個獨特的索引,因此添加額外的索引對速度沒有影響。它根據計劃使用WHERE子句的PRIMARY索引。 – Orbling 2010-11-19 20:19:26

0

我並不熟悉mysql,但ib.id上的索引幾乎肯定會有所幫助。您在JOIN或WHERE子句中使用的任何字段通常應該被編入索引。此外,你可以嘗試過濾i.import_bundle_id而不是ib.id,看看是否有幫助。

索引通常用於加快查找信息的速度。與其不必遍歷遍佈整個數據庫的每個項目來找到合適的項目,他們可以使用散列表或類似的方法來縮小它們必須查看的範圍,可能將範圍縮小到正確的記錄。 Wikipedia explains it遠比我可以。 :)

0

其他答案指出你在正確的方向至ib.id索引。但是,ib.id看起來像主鍵(PK)。它在數據庫中設置爲PK嗎?如果是這樣,它應該通過成爲一名PK自動獲得索引。如果它沒有設置爲PK,並且確實是應爲的列,那麼數據庫的問題不僅僅是性能問題。

簡而言之,如果ib.id應該是一個主鍵,那麼將其設爲1,並且您的性能應該會提高,因爲它會自動獲取索引(並且您不必擔心單獨向其中添加任何索引)。

+0

這是一個PK。出於某種原因,堆棧溢出註釋必須至少有一定的長度,所以我在這裏輸入更多的東西。 – 2010-11-19 20:05:51