我有两个表,表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";
}
}
我希望查询能够快速进行,但出于某种原因,它并不是很快。我对select的解释(具有特定值“number”)给出了以下内容:
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
答案 0 :(得分:4)
您正在尝试查找包含点的间隔。对于B-tree索引(大多数数据库中的默认索引类型),这不是那么快,但R-tree索引适用于此类查询。 MySQL不允许您直接更改索引的类型,但您可以通过使用GEOMETRY列类型强制MySQL使用R-Tree。
Quassnoi在his article on nested sets in MySQL中介绍了这一点。虽然它不完全相同,但它非常相似。引文来自文章:
还有一类任务 需要搜索所有范围 包含已知值:
* Searching for an IP address in the IP range ban list * Searching for a given date within a date range
和其他几个人。这些任务可以 通过使用R-Tree功能进行了改进 的MySQL
答案 1 :(得分:2)
我认为您在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
的查询创建的索引,因此您可以删除该索引。
答案 2 :(得分:1)
首先,我假设所需的输出是对输入所在的所有“源”进行分组 number_e和number_s及其计数。
我对语法很苛刻,但您可能会考虑在那里使用'BETWEEN'子句而不是使用less-than / greater-than运算符进行显式比较
编辑:Zombat说的也适用;索引也会有所帮助。