通过php计算行数比SQL中的COUNT快?

时间:2013-11-17 03:02:16

标签: php mysql sql

简而言之,我的问题是:为什么这是

SELECT r.x, r.y FROM `base` AS r
WHERE r.l=50 AND AND r.n<>'name' AND 6=(SELECT COUNT(*) FROM surround AS d 
    WHERE d.x >= r.x -1 AND d.x <= r.x +1 AND 
          d.y>=r.y -1 AND d.y<=r.y +1 AND d.n='name')

比这慢很多:

$q="SELECT x,y FROM `base` WHERE l=50 AND n<>'name'";
$sr=mysql_query($q);
if(mysql_num_rows($sr)>=1){
    while($row=mysql_fetch_assoc($sr)){
        $q2="SELECT x,y FROM surround WHERE n='name' AND x<=".
            ($row["x"]+1)." AND x>=".($row["x"]-1).
            " AND y<=".($row["y"]+1)." AND y>=".($row["y"]-1)." ";
        $sr2=mysql_query($q2);
        if(mysql_num_rows($sr2)=6){
            echo $row['x'].','.$row[y].'\n';
        }
    }
}

php版本需要大约300毫秒才能完成,如果我运行“纯SQL”版本,无论是通过phpadmin还是通过php,大约需要5秒钟(当我使用BETWEEN用于x的那些范围时,甚至需要13秒)和y)

我怀疑SQL版本通常会更快,更有效率,所以我想知道,我做错了什么,或者它有意义吗?

编辑:我按要求添加了两个表的结构:

CREATE TABLE IF NOT EXISTS `base` (
  `bid` int(12) NOT NULL COMMENT 'Base ID',
  `n` varchar(25) NOT NULL COMMENT 'Name',
  `l` int(3) NOT NULL,
  `x` int(3) NOT NULL,
  `y` int(3) NOT NULL,
  `LastModified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY `coord` (`x`,`y`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `surround` (
  `bid` int(12) NOT NULL COMMENT 'Base ID',
  `n` varchar(25) NOT NULL COMMENT 'Name',
  `l` int(3) NOT NULL,
  `x` int(3) NOT NULL,
  `y` int(3) NOT NULL,
  `LastModified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY `coord` (`x`,`y`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

编辑2:

以上查询的EXPLAIN SELECT :(键坐标是x和y的组合)

id  select_type         table   type    possible_keys   key     key_len     ref     rows    Extra   
1   PRIMARY             r       range   coord,n         coord   4           NULL    4998    Using where
2   DEPENDENT SUBQUERY  d       ALL     coord           NULL    NULL        NULL    57241   Range checked for each record (index map: 0x1)

1 个答案:

答案 0 :(得分:2)

你自己加入两张桌子。你是一个优化者。你选择'base'表是嵌套循环连接的外表。我猜MySQL的优化器产生了执行计划,它和你不一样。

所以人们希望EXPLAIN输出看到连接顺序并检查是否使用了索引。

顺便问一下,你可以尝试这个查询吗?:

SELECT r.x, r.y
FROM `base` AS r, surround AS d
WHERE r.l=50
  AND r.n<>'name'
  AND d.x >= r.x -1
  AND d.x <= r.x +1
  AND d.y>=r.y -1
  AND d.y<=r.y +1
  AND d.n='name'
GROUP BY r.x, r.y
HAVING COUNT(*) = 6

<强>已更新

原始查询的工作原理

这是第一次看到Range checked for each record (index map: 0x1)所以我无法弄清楚您的查询是如何工作的。 MySQL Manual为我们提供了一些相关信息。似乎surroundsurround中有57k行?)的每一行都与base的x,y进行比较。如果是这样,则使用3深度嵌套循环连接评估查询。 (base =&gt; surround =&gt; base)而且surround中的每一行都被比较(这是低效的)

我会更加努力地找到它以后如何运作。是时候工作了。