Php 我还能做些什么来优化这个MySQL查询吗?

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 | +-----------+---------------------+------+-----+--------

我有两个表,表A有700000个条目,表B有600000个条目。结构如下:

表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    |                |
+-------------+---------------------+------+-----+---------+----------------+
我尝试使用以下代码查找表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