2012-06-12 33 views
0

我有以下MySQL查詢:MySQL的分手左表中LEFT JOIN的查詢性能增強

SELECT pool.username 
FROM pool 
LEFT JOIN sent ON pool.username = sent.username 
AND sent.campid = 'YA1LGfh9' 
WHERE sent.username IS NULL 
AND pool.gender = 'f' 
AND (`location` = 'united states' OR `location` = 'us' OR `location` = 'usa'); 

的問題是,池表包含數百萬行的這個查詢需要超過12分鐘才能完成。我意識到在這個查詢中,整個左表(池)正在被掃描。池表具有自動遞增的id行。

我想將此查詢拆分爲多個查詢,以便不掃描整個池表,我一次掃描1000行,並在下一個查詢中,我將選擇離開的地方(1000-2000,2000- 3000)等等使用id列來跟蹤。

如何在我的查詢中指定此項?如果你知道答案,請舉例說明。謝謝。

這裏是我的指標,如果有幫助:

mysql> show index from main.pool; 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| pool |   0 | PRIMARY |   1 | id   | A   |  9275039 |  NULL | NULL |  | BTREE  |   | 
| pool |   1 | username |   1 | username | A   |  9275039 |  NULL | NULL |  | BTREE  |   | 
| pool |   1 | source |   1 | source  | A   |   1 |  NULL | NULL |  | BTREE  |   | 
| pool |   1 | location |   1 | location | A   |  38168 |  NULL | NULL |  | BTREE  |   | 
| pool |   1 | pdex  |   1 | gender  | A   |   2 |  NULL | NULL |  | BTREE  |   | 
| pool |   1 | pdex  |   2 | username | A   |  9275039 |  NULL | NULL |  | BTREE  |   | 
| pool |   1 | pdex  |   3 | id   | A   |  9275039 |  NULL | NULL |  | BTREE  |   | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
8 rows in set (0.00 sec) 

mysql> show index from main.sent; 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| sent |   0 | PRIMARY |   1 | primary_key | A   |   351 |  NULL | NULL |  | BTREE  |   | 
| sent |   1 | username |   1 | username | A   |   175 |  NULL | NULL |  | BTREE  |   | 
| sent |   1 | sdex  |   1 | campid  | A   |   7 |  NULL | NULL |  | BTREE  |   | 
| sent |   1 | sdex  |   2 | username | A   |   351 |  NULL | NULL |  | BTREE  |   | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 

,這裏是我的查詢的解釋:

----------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra        | 
+----+-------------+-------+-------+---------------+------+---------+-------+---------+--------------------------------------+ 
| 1 | SIMPLE  | pool | ref | location,pdex | pdex | 5  | const | 6084332 | Using where       | 
| 1 | SIMPLE  | sent | index | sdex   | sdex | 309  | NULL |  351 | Using where; Using index; Not exists | 
+----+-------------+-------+-------+---------------+------+---------+-------+---------+--------------------------------------+ 

這裏的檯球桌的結構:

| pool | CREATE TABLE `pool` (
`id` int(20) NOT NULL AUTO_INCREMENT, 
`username` varchar(50) CHARACTER SET utf8 NOT NULL, 
`source` varchar(10) CHARACTER SET utf8 NOT NULL, 
`gender` varchar(1) CHARACTER SET utf8 NOT NULL, 
`location` varchar(50) CHARACTER SET utf8 NOT NULL, 
PRIMARY KEY (`id`), 
KEY `username` (`username`), 
KEY `source` (`source`), 
KEY `location` (`location`), 
KEY `pdex` (`gender`,`username`,`id`) 
) ENGINE=MyISAM AUTO_INCREMENT=9327026 DEFAULT CHARSET=latin1 | 

這裏是發送表的結構:

| sent | CREATE TABLE `sent` (
`primary_key` int(50) NOT NULL AUTO_INCREMENT, 
`username` varchar(50) NOT NULL, 
`from` varchar(50) NOT NULL, 
`campid` varchar(255) NOT NULL, 
`timestamp` int(20) NOT NULL, 
PRIMARY KEY (`primary_key`), 
KEY `username` (`username`), 
KEY `sdex` (`campid`,`username`) 
) ENGINE=MyISAM AUTO_INCREMENT=352 DEFAULT CHARSET=latin1 | 

這會產生一個語法錯誤,但是這其中初條款是林後:喜歡它的使用pool.location 可以試試性別上添加索引,可能沒有很多

SELECT pool.username 
FROM pool 
WHERE id < 1000 
LEFT JOIN sent ON pool.username = sent.username 
AND sent.campid = 'YA1LGfh9' 
WHERE sent.username IS NULL 
AND pool.gender = 'f' 
AND (location = 'united states' OR location = 'us' OR location = 'usa'); 
+0

此查詢返回多少行? 「位置」是「泳池」的一列嗎? –

+0

此查詢目前返回超過600萬行。位置是一個池的列。 – xendi

+0

你有沒有索引?你對600萬行做了什麼? –

回答

0

拆分您的查詢聽起來不像正確的方法。

更好的方法是從現有查詢中獲取一些記錄,發送消息並繼續提取。


你的查詢可以從另一種化合物指數受益於

pool(location, gender, username) 

這應該允許運行從sdex你的完整的查詢和你的新指標。


如果你真的要拆分的查詢,一個簡單的辦法可以是

SELECT MIN(id), MAX(id) FROM pool 

,然後從分環路最多在1000步驟,並添加id >= r AND id < r+1000到您的查詢。

如果您有間隙,這可能會返回0行,但它不會一次返回超過1000行。包括(idlocationgenderusername)在內的pool上的不同化合物索引可能有助於此查詢。

+0

我會這樣做,但即使在使用位置列之前,查詢時間也是如此。我真的想在查詢中拆分池表,以便我可以使用多個查詢。 – xendi

+0

查看我的編輯.... –

+0

我打算循環使用PHP的步驟1000。是否可以在查詢中指定開始和結束ID?我不認爲只是將其添加到查詢的最後才能實現目標。在哪裏/如何添加,以便它只掃描1個查詢中的池表的x-y標識? – xendi

0

看起來的幫助。 將位置合理化爲數據中的國家/地區代碼以及可能有用的索引編制。

但是,第一個添加的索引看起來對我很重要,這可能會嚴重影響它要測試的記錄數量。

+0

性別是pdex索引的一部分,campid是索引索引的一部分 – xendi