Php 我还能做些什么来优化这个MySQL查询吗?
我有两个表,表A有700000个条目,表B有600000个条目。结构如下: 表A:Php 我还能做些什么来优化这个MySQL查询吗?,php,stored-procedures,mysql,query-optimization,Php,Stored Procedures,Mysql,Query Optimization,我有两个表,表A有700000个条目,表B有600000个条目。结构如下: 表A: +-----------+---------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------------------+------+-----+--------
+-----------+---------------------+------+-----+---------+----------------+
| 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 | |
+-------------+---------------------+------+-----+---------+----------------+
我尝试使用以下代码查找表A中的任何值是否存在于表B中:
$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";
}
}
$sql=“从表A中选择数字”;
$result=mysql\u query($sql)或die(mysql\u error());
while($row=mysql\u fetch\u assoc($result)){
$number=$row['number'];
$sql=“从表B中选择源、计数(源),其中编号<$number和编号<$number按源分组”;
$re=mysql\u query($sql)或die(mysql\u错误);
而($ro=mysql\u fetch\u数组($re)){
回显$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)
mysql>解释选择源,从表B中计数(源),其中数字s<1812194440和数字e>1812194440按源分组;
+----+-------------+------------+------+-------------------------+------+---------+------+--------+----------------------------------------------+
|id |选择|类型|类型|可能的|键|键|列|参考|行|额外|
+----+-------------+------------+------+-------------------------+------+---------+------+--------+----------------------------------------------+
|1 |简单|表格B |全部|数字| s,数字| e | NULL | NULL | NULL | 696325 |使用where;使用临时设备;使用filesort|
+----+-------------+------------+------+-------------------------+------+---------+------+--------+----------------------------------------------+
一行一组(0.00秒)
我能从中挤出任何优化吗
我尝试为同一个任务编写一个存储过程,但它似乎一开始就不起作用。。。它没有给出任何语法错误。。。我试着跑了一天,它仍然在跑,感觉很奇怪
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
创建过程过滤器()
开始
声明数字BIGINT无符号;
声明x INT;
声明完成INT默认值为0;
为表A中的SELECT number声明cur1游标;
为未找到的集合声明CONTINUE处理程序done=1;
如果不存在标志(数字bigint unsigned,计数int(11)),则创建临时表;
开放cur1;
历史循环:循环
把cur1取到数字中;
从表格B中选择计数(*),其中数字s<数字和数字e>数字进入x;
如果完成=1,则
离开hist_循环;
如果结束;
如果x不为NULL且x>0,则
插入标志(数字,计数)值(数字,x);
如果结束;
结束循环hist_循环;
关闭cur1;
结束
在我看来,在编号
和编号
列上有单独的索引,可能是用单独的添加索引(编号)
和添加索引(编号)
列创建的
如果您添加一个包含这两列的索引,您可能会获得更好的性能,因为它们都在您的查询中使用,而且MySQL显然没有选择使用这两个单列索引中的任何一个,这表明整个表扫描会更快(如果您的查询跨越一个大范围的值,这并不少见)
在此之后,您不需要单独的
number\s
索引,因为MySQL可以使用您刚刚创建的索引来查询number\s
,所以您最好删除该索引。您正在尝试查找包含点的间隔。这对于索引(大多数数据库中的默认索引类型)来说不是很快,但是索引对于这种查询很有效。MySQL不允许您直接更改索引的类型,但是您可以通过使用GEOMETRY列类型强制MySQL使用R树
包括这一点。虽然不完全一样,但非常相似。文章引述:
还有一类特定的任务
这需要搜索所有范围
包含已知值的:
* Searching for an IP address in the IP range ban list
* Searching for a given date within a date range
还有其他几个。这些任务可以是
通过使用R-Tree功能进行改进
MySQL的应用
首先,我假设所需的输出是将输入所在的所有“源”分组 数字e和数字s及其计数
我对语法很粗浅,但是你可以考虑使用一个“两个”子句,而不是使用比操作符
小于/大于的一个显式比较。编辑:僵尸说的也适用;索引也会有帮助。让我直说吧。。。您正在运行70001个查询,并且您对它的速度不快感到惊讶?嗯。。我不是说它不快。。我只是想问,我是否可以做更多的优化来加快速度…:)如果在数字和数字之间使用
$number
,是否会比较慢?实际上没有观察到性能差异。当然,我没有放计时语句,只是观察了echo命令的输出。然后数据库可以优化1个查询,而不是处理700k+个查询,并为组合索引带来+1的所有开销。没有观察到太多的差异,但我会继续尝试建议的R-树。谢谢虽然这个答案可能就是这个问题的答案,但当有人对表1中的所有记录使用这样的代码时,我仍然感到很有趣。。。来自表2,其中条件基于表1中的内容
。加入是一个更自然的思维方向。@extraneon:的确,如果你读了这篇文章,你会发现这正是Quassnoi所建议的,例如,加入MBRINSON上的层次hrp(点(0,hp.lft),hrp.set)
。虽然在这里你不需要所有的间隔,但知道有一个间隔就足够了。@MarkByers:只需要t
* Searching for an IP address in the IP range ban list
* Searching for a given date within a date range