2013-05-03 82 views
1

使用MySQL 5.5與InnoDB。 有像低基數指數仍然減慢查詢速度

SELECT 
     count(distinct a.thing_id) as new_thing_count, 
     sum(b.price) as new_thing_spend 
    FROM thing ii 
    LEFT OUTER JOIN thing a 
     ON a.customer_id = ii.customer_id 
     AND a.created_at >= '2013-01-01' 
     AND a.created_at <= '2013-03-31' 
    JOIN whatsit b 
     ON b.whatsit_id = a.original_whatsit_id 
    WHERE ii.customer_id = 3 

其中

  • thing約爲25K基數,其中3.5K查詢屬於客戶3
  • 有12種可能customer_id小號

現在,當我使用customer_id上的索引運行此查詢時,大約需要10秒。當我放棄索引時,需要0.03秒。

我不明白爲什麼這可能是。這裏是沒有指標解釋的結果:

1 SIMPLE ii ALL     24937 Using where 
1 SIMPLE a ALL     24937 Using where; Using join buffer 
1 SIMPLE b eq_ref PRIMARY PRIMARY 4 db.a.original_whatsit_id 1 

在這裏它與索引(thing_customer

1 SIMPLE ii ref thing_customer thing_customer 4 const 3409 Using index 
1 SIMPLE a ref thing_customer thing_customer 4 const 3409 Using where 
1 SIMPLE b eq_ref PRIMARY PRIMARY 4 db.a.original_whatsit_id 1 

有人可以幫我解釋爲什麼這個指標是速度變慢時,邏輯上它不那麼大看起來應該是這樣嗎?

回答

2

當您的數據庫引擎決定讀取索引時,它會依次讀取一行。這可能導致它讀取磁盤頁面2中的行,第4頁中的另一個,第1頁中的另一個,第2頁中的下一個等等。

有時,來回是這樣的,索引不會去幫助 - 相反。

如果數據庫引擎在生成查詢計劃時在收集和分析表上的統計信息方面做得不好,它可能不會識別該索引會產生完全分段的磁盤讀取。這可能是你正在經歷的。

嘗試分析表來收集新的統計:

http://dev.mysql.com/doc/refman/5.5/en/analyze-table.html

然後使用和不使用索引重試。

+0

似乎是合理的建議,但實際上它沒有加快查詢的速度......事實上,數據似乎非常有可能極其分散。這種情況下沒有什麼可以做的嗎? – Colleen 2013-05-03 22:50:27

+0

好吧,如果您經常查詢一個字段,您可以在其上創建一個聚集索引,以便相應地對錶進行排序。在你的情況下,'(customer_id,created_at)'上的一個實際上可能有意義。 – 2013-05-03 22:58:45

+0

如果數據不敏感,你可以做的另一件事是在mysql上報告錯誤。規劃師應該比使用索引更好,因爲這意味着要在整個地方來回讀取行。 (Postgres,fwiw,在這方面做得非常好,如果切換是可能的話)。 – 2013-05-03 23:00:30