简而言之,我的问题是:为什么这个
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秒(当我对x和y的范围使用BETWEEN时,甚至需要13秒)
我怀疑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:
解释上面查询的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)
您正在自己连接两个表。你是一个优化器。您选择"base"表是嵌套循环联接的外部表。我猜MySQL的优化器生成了执行计划,但它和您不一样。
所以人们希望CCD_ 1的输出能够查看联接顺序并检查是否使用了索引。
顺便问一下,你能试试这个查询吗?:
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手册给了我们一些关于它的信息。似乎surround
中的每一行(surround
有57k行?)都与base
的x,y相比较。如果是这样,则使用3深度嵌套循环联接来评估查询。(基本=>环绕=>基本)并且此外比较surround
中的每一行(这是低效的)
我以后会花更多的精力来了解它是如何工作的。该上班了。