2013-10-18 125 views
0

發生奇怪的事情。任何人都可以請解釋。 我有一張桌子。在MySQL中使用索引

CREATE TABLE "country_ip" (
    "begin_ip" varchar(15) NOT NULL, 
    "end_ip" varchar(15) NOT NULL, 
    "begin_ip_long" int(10) unsigned NOT NULL, 
    "end_ip_long" int(10) unsigned NOT NULL, 
    "id" char(2) NOT NULL, 
    "label" varchar(50) NOT NULL, 
    KEY "begin_ip_long" ("begin_ip_long","end_ip_long"), 
    KEY "end_ip_long" ("end_ip_long") 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

約有150 000條記錄。 下一查詢具有巨大的時間差

0.06329400 | SELECT * FROM `country_ip` WHERE '1405662435' BETWEEN `begin_ip_long` AND `end_ip_long` LIMIT 1 
0.06214600 | SELECT * FROM `country_ip` USE INDEX (begin_ip_long, end_ip_long) WHERE 1405662435 BETWEEN `begin_ip_long` AND `end_ip_long` LIMIT 1 
0.00008400 | SELECT * FROM `country_ip` USE INDEX (end_ip_long) WHERE 1405662435 BETWEEN `begin_ip_long` AND `end_ip_long` LIMIT 1 

任何人都可以解釋它爲什麼會發生?我的意思是,爲什麼只有USE INDEX(end_ip_long)同時使用USE INDEX(begin_ip_long)USE INDEX(begin_ip_long,end_ip_long)沒有效果有所幫助。謝謝。

+0

'誰能解釋嗎?有趣的是,MySQL本身可以「最好地解釋」:) –

+0

你需要一個R-Tree(空間)索引。 – eggyal

+0

看起來像InnoDB不支持空間索引。無論如何它不能解釋任何東西 – user2893612

回答

1

也許這是因爲索引(end_ip_long)小於(begin_ip_long, end_ip_long),它適合內存和一列是足夠選擇性的。雖然較大的索引可能需要從磁盤讀取。

+0

不可以,因爲(begin_ip_long)可以快速運行0.00007600 | SELECT * FROM'country_ip' USE INDEX(begin_ip_long)WHERE'begin_ip_long' <= 1405662435 LIMIT 1 – user2893612

+0

這並不意味着什麼。 alexius懇求MySQL爲什麼選擇end_ip_long,我認爲他是對的。你可以不同意MySQL的優化器,但它仍然遵循它的規則。無論如何,當提問這樣的問題時,你應該提供EXPLAIN的輸出。 SELECT的時間沒有多大意義,對LIMIT 1沒有任何意義。 –

1

由於您可以使單列(END_IP_LONG)索引快速運行,爲什麼不只是在一列上索引&?

我可能會使用BEGIN_IP_LONG並搜索第一個記錄,其中指定的IP是> = country.BEGIN_IP_LONG,通過IP降序排列,限制爲1.應該檢索「floor」條目,然後執行所有操作檢查指定的IP是否不超過該國的END_IP_LONG。

這將正確完成查找,只使用單列索引。 (所有這些假設的範圍沒有重疊,我以爲是真的給你規定的結構。)


正如其他人建議,調查MySQL的計劃(也許重建統計數據)將是值得的 - 但在技術上,非重疊範圍查找在技術上應該是可能的,只使用單個邊界上的索引。