2012-04-13 104 views
2

this wiki article,我發現如果在MySQL數據庫中使用帶索引列的IN()子句,SELECT性能會被終止。我的問題是,如何重寫我的查詢,以便它不會使用任何IN()子句,同時仍然保持其功能?使用IN()子句優化查詢

我的查詢是:

SELECT 
    `Route`.`route_id`, `Route`.`order`, `Route2`.`order` 
FROM 
    `routes` AS `Route` 
INNER JOIN 
    `routes` AS `Route2` 
ON `Route`.`route_id` = `Route2`.`route_id` 
WHERE 
    `Route`.`station_line_id` IN ([10 values]) AND 
    `Route2`.`station_line_id` IN ([10 values]) AND 
    `Route`.`order` <= `Route2`.`order` 
GROUP BY ` 
    `Route`.`station_line_id`, `Route2`.`station_line_id`, (`Route2`.`order` - `Route`.`order`) 

,我已經索引的所有列(ROUTE_ID,station_line_id,station_id和line_id),與id列是主鍵(表只是只讀一旦產生,所以不用擔心索引一切)。 IN()子句中的[10 values]用逗號分隔,如:IN(1, 2, ..., 10)

基本上,我自己加入表路由表並將結果分組以獲得所需的記錄。其他連接用於檢索關聯的數據。

性能方面,使用InnoDB存儲引擎,我在> 30秒內執行類似的查詢。使用MyISAM,我會得到> 5秒。但我相信結果可以更快取得。表中有450萬條記錄。

+0

小心地格式化您的查詢一點點? – 2012-04-13 15:17:46

+0

我編輯了我的問題,對不起。 – linkyndy 2012-04-13 15:20:15

+0

這10個值是:IN(1,3,47,... 89)還是IN(SELECT column from table)? – 2012-04-13 15:25:16

回答

1

您將在使用'哈希索引'的查詢中獲得最佳性能。 '標準'索引是一個B +樹,它允許您在log(n)時間查找條目,其中n是表中的行數。他們還保持排序的順序,所以你可以有效地進行查詢,如... WHERE station_line_id > 14,所以這就是你想要在你的Order列上使用的。

但是,對於您的情況,使用IN子句,您只能查找等同性。在這種情況下,B +樹將不得不單獨查找所有m個「[10個值]」,花費你m * log(n)時間,這顯然需要5-30秒。

散列索引用於在恆定的時間量(非常快)中查找等價條目,這並不依賴於(理論上)表中的行數 - 即使在大的情況下它也總是非常快表。散列索引的缺點是不能用它來執行像<>這樣的查詢,但它在等效查詢中的速度最快,就像您在station_line_idIN子句中執行的那樣。

編輯:對於MySQL來說,不幸的是他們不支持任何他們流行的數據庫引擎上的HASH索引。如果您能夠使用MEMORY或HEAP引擎,那麼您可以使用HASH索引 - 並且讓內存中的所有內容都可能提高性能。值得一試。

+0

我目前在共享主機上,我認爲將這些數據存儲在內存中不是一個選項(或?)。 – linkyndy 2012-04-13 15:37:37

+1

MyISAM和InnoDB沒有哈希索引。 – 2012-04-13 15:37:48

+0

依您的數據結構而定,仍值得一試。我有一張4500萬行表,適合2.7GB的數據和1.1GB的索引。按照這個速度,你的表格可能會佔用大約0.27 + .11 GB <= 400MB的內存。我不知道你的服務器要求是什麼,但512MB對於VPS來說並不是不合理的內存量。不確定這是否是您的選擇,但我可以保證提高性能。 – 2012-04-13 15:46:08