2011-09-25 109 views
5

我有一個InnoDB MySql地理標識表,有大約100萬行。該表的結構是這樣的:如何進一步優化這個MySQL表的單個查詢

CREATE TABLE `geoid` (
    `start_ip` int(11) NOT NULL, 
    `end_ip` int(11) NOT NULL, 
    `city` varchar(64) NOT NULL, 
    `region` char(2) NOT NULL, 
    PRIMARY KEY (`start_ip`,`end_ip`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

只會有一種類型的查詢運行對這個表:

SELECT city, region FROM geoid WHERE 1259650516 BETWEEN start_ip AND end_ip 

這個查詢約需〜0.4228秒,這是不超慢,但不是快得令人難以置信醚。

我的問題是:如何進一步優化我的表,這個單一的查詢?

我曾嘗試以下的事情:

  1. 改變存儲引擎MyISAM數據,本作的查詢需要大約1.9秒。
  2. 使用WHERE語句'WHERE geoid.start_ip < = 1259650516 AND 1259650516 < = geoid.end_ip'。但這需要約0.5秒來執行,而不是.4 ish。

我已經從表中刪除了所有無用的行,使它變小。我需要所有100萬行。

UPDATE /解決方案

由於下面的文章,這裏是我做過什麼來解決這個問題。 (只是爲了完成這個答案對於任何人感興趣)

我添加了一個新的列上表:

ALTER TABLE `geoid` ADD `geoip` LINESTRING NOT NULL 

然後,我從start_ip地理數據填充新列和起點ip-終點

GeomFromText(CONCAT('LINESTRING(', start_ip, ' -1, ', end_ip, ' 1)')) 

我然後創建空間索引對新列

CREATE SPATIAL INDEX geoip_index ON geoid(geoip); 

從那裏,所有的你必須做的是改變你的查詢爲:

SELECT city, region FROM geoid WHERE MBRContains(geoip, GeomFromText(CONCAT('POINT(', 1259650516, ' 0)'))); 

和你的完成。這將查詢從.42秒降至.0003秒!!!!!!!

我喜歡這個INDEX。謝謝。希望能幫助到你。

+0

您在'InnoDB'表上創建了一個'SPATIAL'索引? – Quassnoi

+0

我先將它轉換爲MyISAM。 – RonSper

回答

3

嘗試在end_ip上添加索引。在某些情況下,這應該使查詢快兩倍。

對於更好的性能,您需要使用SPATIAL索引,如this article中所述。

+1

除了主要?像:PRIMARY KEY('start_ip','end_ip'), KEY'start_ip'('start_ip'), KEY'end_ip'('end_ip')。這並沒有改變任何事情。 – RonSper

+0

@Ron的Sper:那麼它不會加快在所有情況下的查詢,並只給在其他情況下,一個相對較小的速度了。如果你想要更好的表現,你可能需要考慮一個SPATIAL索引。看到這篇文章:http://explainextended.com/2009/09/29/adjacency-list-vs-nested-sets-mysql/。但它不適合初學者。 –

+1

WOW,那是完美的。這正是我想要的。謝謝。 – RonSper

0

嘗試在查詢中包含的所有字段上創建索引。在這個特殊情況下在兩個字段(start_ip和end_ip)上創建一個索引