[英]Is there anything else I can do to optimize this MySQL query?
我有兩個表,表A有700,000項,表B有600,000項。 結構如下:
表A:
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| number | bigint(20) unsigned | YES | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
表B:
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| number_s | bigint(20) unsigned | YES | MUL | NULL | |
| number_e | bigint(20) unsigned | YES | MUL | NULL | |
| source | varchar(50) | YES | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
我正在嘗試使用以下代碼查找表B中是否存在表A中的任何值:
$sql = "SELECT number from TableA";
$result = mysql_query($sql) or die(mysql_error());
while($row = mysql_fetch_assoc($result)) {
$number = $row['number'];
$sql = "SELECT source, count(source) FROM TableB WHERE number_s < $number AND number_e > $number GROUP BY source";
$re = mysql_query($sql) or die(mysql_error);
while($ro = mysql_fetch_array($re)) {
echo $number."\t".$ro[0]."\t".$ro[1]."\n";
}
}
我希望查詢能夠快速進行,但是由於某種原因,查詢速度並不快。 我對選擇的解釋(特定值為“數字”)為我提供了以下內容:
mysql> explain SELECT source, count(source) FROM TableB WHERE number_s < 1812194440 AND number_e > 1812194440 GROUP BY source;
+----+-------------+------------+------+-------------------------+------+---------+------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+-------------------------+------+---------+------+--------+----------------------------------------------+
| 1 | SIMPLE | TableB | ALL | number_s,number_e | NULL | NULL | NULL | 696325 | Using where; Using temporary; Using filesort |
+----+-------------+------------+------+-------------------------+------+---------+------+--------+----------------------------------------------+
1 row in set (0.00 sec)
我可以從中得到什么優化嗎?
我嘗試為同一任務編寫存儲過程,但它似乎一開始就沒有起作用……它沒有給出任何語法錯誤……我嘗試運行了一天,但仍在運行感到奇怪。
CREATE PROCEDURE Filter()
Begin
DECLARE number BIGINT UNSIGNED;
DECLARE x INT;
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT number FROM TableA;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
CREATE TEMPORARY TABLE IF NOT EXISTS Flags(number bigint unsigned, count int(11));
OPEN cur1;
hist_loop: LOOP
FETCH cur1 INTO number;
SELECT count(*) from TableB WHERE number_s < number AND number_e > number INTO x;
IF done = 1 THEN
LEAVE hist_loop;
END IF;
IF x IS NOT NULL AND x>0 THEN
INSERT INTO Flags(number, count) VALUES(number, x);
END IF;
END LOOP hist_loop;
CLOSE cur1;
END
您正在嘗試查找包含點的間隔。 使用B樹索引(大多數數據庫中的默認索引類型)的速度不是很快,但是R樹索引對於這種查詢將非常有效。 MySQL不允許您直接更改索引的類型,但是您可以通過使用GEOMETRY列類型來強制MySQL使用R-Tree。
Quassnoi在他有關MySQL嵌套集的文章中對此進行了介紹 。 雖然並不完全相同,但非常相似。 文章引用:
還有一類任務需要搜索包含已知值的所有范圍:
* Searching for an IP address in the IP range ban list * Searching for a given date within a date range
和其他幾個。 通過使用MySQL的R-Tree功能可以改善這些任務
在我看來,您在number_e
和number_s
列上具有單獨的索引,可能是通過單獨的ADD INDEX(number_e)
和ADD INDEX(number_s)
列創建的。
如果添加一個包含這兩個列的索引,則可能會獲得更好的性能,因為它們都在查詢中使用,並且MySQL顯然不選擇使用任何一個單列索引,從而判斷了整個表的掃描會更快(如果您的查詢跨越較大范圍的值,這種情況並不罕見)。
ALTER TABLE tblB ADD INDEX(number_s,number_e);
在那之后,您將不需要單獨的number_s
索引,因為MySQL只能將您剛創建的索引用於對number_s
查詢,因此您最好刪除該索引。
首先,我假設期望的輸出是將輸入位於number_e和number_s之間的所有“源”及其計數進行分組。
我對語法不滿意,但您可能會考慮在此處使用“ BETWEEN”子句,而不是使用小於/大於大於運算符進行顯式比較
編輯:Zombat所說的也適用; 索引也會有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.