2011-12-23 65 views
0

慢我有一個表的150萬記錄(ip2country),我執行下面的查詢這需要超過4秒 我的表結構MySQL查詢的WHERE條件大表

CREATE TABLE `ip2country` (
    `beginIPNum` bigint(20) DEFAULT NULL, 
    `endIPNum` bigint(20) DEFAULT NULL, 
    `countryId` varchar(4) DEFAULT NULL, 
    `countryName` varchar(50) DEFAULT NULL, 
    `state` varchar(50) DEFAULT NULL, 
    `city` varchar(50) DEFAULT NULL, 
    KEY `index1` (`beginIPNum`,`endIPNum`) USING BTREE 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 
PARTITION BY RANGE COLUMNS(beginIPNum,endIPNum) 
(PARTITION p0 VALUES LESS THAN (16777216,16777216) ENGINE = MyISAM, 
PARTITION p1 VALUES LESS THAN (251658240,251658240) ENGINE = MyISAM, 
PARTITION p2 VALUES LESS THAN (503316480,503316480) ENGINE = MyISAM, 
PARTITION p3 VALUES LESS THAN (754974720,754974720) ENGINE = MyISAM, 
PARTITION p4 VALUES LESS THAN (1006632960,1006632960) ENGINE = MyISAM, 
PARTITION p5 VALUES LESS THAN (1258291200,1258291200) ENGINE = MyISAM, 
PARTITION p6 VALUES LESS THAN (1509949440,1509949440) ENGINE = MyISAM, 
PARTITION p7 VALUES LESS THAN (1761607680,1761607680) ENGINE = MyISAM, 
PARTITION p8 VALUES LESS THAN (2013265920,2013265920) ENGINE = MyISAM, 
PARTITION p9 VALUES LESS THAN (2264924160,2264924160) ENGINE = MyISAM, 
PARTITION p10 VALUES LESS THAN (2516582400,2516582400) ENGINE = MyISAM, 
PARTITION p11 VALUES LESS THAN (2768240640,2768240640) ENGINE = MyISAM, 
PARTITION p12 VALUES LESS THAN (3019898880,3019898880) ENGINE = MyISAM, 
PARTITION p13 VALUES LESS THAN (3271557120,3271557120) ENGINE = MyISAM, 
PARTITION p14 VALUES LESS THAN (3523215360,3523215360) ENGINE = MyISAM, 
PARTITION p15 VALUES LESS THAN (3774873600,3774873600) ENGINE = MyISAM, 
PARTITION p16 VALUES LESS THAN (4294967295,4294967295) ENGINE = MyISAM) 

SELECT beginIPNum,endIPNum,countryId,countryName 
FROM sdportallog.ip2country 
WHERE 2130706433 BETWEEN beginIPNum AND endIPNum 

誰能幫助我好嗎?

+2

是否beginIPNum和endIPNum設置爲指標? – loganfsmyth 2011-12-23 06:01:39

+0

關於您所能做的只是增加mysql的鍵緩存大小,或將表分成多個較小的表,以便可以緩存單個表的鍵。 – 2011-12-23 06:07:22

+0

只是一個關於數據粒度的問題......因爲看起來你只是在尋找IP地址的國家,你真的需要150萬條記錄嗎?每2500個IPv4地址大約有1個記錄。 (編輯:剛剛下載了一個,約113,000條記錄) – 2011-12-23 06:08:19

回答

1

嘗試

SELECT beginIPNum,endIPNum,countryId,countryName 
FROM sdportallog.ip2country    
WHERE beginIPNum <= 2130706433 AND endIPNum >= 2130706433 
+0

我試過了,但也需要4.875秒 – 2011-12-23 06:04:15

+1

這個和'between'版本沒有實質區別 - 它們在內部執行相同。'之間'只是句法糖的好處。 – 2011-12-23 06:06:32

+0

確切地說,我能做些什麼來使我的查詢更快? – 2011-12-23 06:09:00

0

查詢優化是創建幾個指標。以下腳本將在表上創建兩個索引,每個字段上一個索引。

-- Create index on IPFrom 
CREATE INDEX index_beginIPNum 
    ON sdportallog.ip2country(beginIPNum) 

-- Create index on IPTo 
CREATE INDEX index_endIPNum 
    ON sdportallog.ip2country(endIPNum) 
0

如果你對索引很好。你可以試試下面的辦法:

  1. 添加分區
  2. 添加另一列到表
  3. 更改查詢

分區:嘗試添加分區(你可以測試範圍和HASH )。正確的策略,您可以自行選擇重新創建表並重新執行查詢。對於HASH,例如可以使用10個分區來啓動。對於RANGE,您可以:

  • inet_aton(1.0.0.0)... inet_aton(255.0.0.0)。無需創建255個分區。
  • 如果任何一組太多的國家每組X.0.0.0存在,你可以嘗試XY0.0

表縮小分區和鴻溝改變: 我想這是很好的做法,添加分區參數作爲列並索引它。但是,請放鬆這一步。

與您相關的更改查詢: 您應該着手爲您的散列/範圍值添加篩選。例如,如果您使用X.0.0.0進行分區,您應該添加類似於where your_added_column = inet_aton(X.0.0.0) and your_base_condition

嘗試使用不同的分區類型和分區數量。

希望它有幫助。

+0

我已經完成了你所說的螞蟻它現在需要大約1秒(感謝你),我必須在毫秒內完成 – 2011-12-28 08:22:00

+0

正如我看到你改變了你的表格,但沒有改變查詢。你正在使用「之間」?你能發佈PLAN嗎? – ravnur 2011-12-28 12:00:56

0

SELECT beginIPNum,endIPNum,countryId,國家名稱 FROM sdportallog.ip2country WHERE 2130706433之間beginIPNum和endIPNum LIMIT 1