我在索引此查询时遇到问题:
SELECT *,
(ROUND(SQRT(
POW(LEAST(ABS(-12 - wdata.x),
ABS(401 - ABS(-12 - wdata.x))), 2) +
POW(LEAST(ABS(45 - wdata.y),
ABS(401 - ABS(45 - wdata.y))), 2)),3)
) AS distance
FROM odata
LEFT JOIN wdata ON wdata.id=odata.vref
WHERE TRUE
HAVING distance<4.9497474683058326708059105347339
ORDER BY distance
LIMIT 30
结果是:
+----+-------------+-------+--------+---------------+---------+---------+-----------------------------+-------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+-----------------------------+-------+---------------------------------+ | 1 | SIMPLE | odata | ALL | NULL | NULL | NULL | NULL | 19118 | Using temporary; Using filesort | | 1 | SIMPLE | wdata | eq_ref | PRIMARY | PRIMARY | 4 | mytravia_1000-14.odata.vref | 1 | NULL | +----+-------------+-------+--------+---------------+---------+---------+-----------------------------+-------+---------------------------------+ 2 rows in set (0.00 sec)
我知道它显示 0.00 秒是执行时间,但是这个查询将运行很多次,并且它显示它会减慢我的数据库,我不知道为什么!
每次我看到此查询的检查行数为 459448,因此出于某些原因,它对我的工作非常不利。
谁能给个建议吗?如何为 odata 表建立正确的索引?或者我可以使用子查询来修复它吗?
表格是:
解释一下odata:
vref int(10) unsigned NO PRI NULL type tinyint(4) NO NULL conqured mediumint(8) unsigned NO NULL wood float(12,2) NO NULL iron float(12,2) NO NULL clay float(12,2) NO NULL woodp float(12,2) NO NULL ironp float(12,2) NO NULL clayp float(12,2) NO NULL maxstore mediumint(8) unsigned NO NULL crop float(12,2) NO NULL cropp float(12,2) NO NULL maxcrop mediumint(8) unsigned NO NULL lasttrain int(10) unsigned NO NULL lastfarmed int(10) unsigned NO NULL lastupdated int(10) unsigned NO NULL loyalty tinyint(4) NO 100 owner smallint(5) unsigned NO 2 name char(45) NO Oasis
并解释 wdata:
id int(10) unsigned NO PRI NULL auto_increment fieldtype tinyint(3) NO NULL oasistype tinyint(3) NO NULL x smallint(5) NO MUL NULL y smallint(5) NO MUL NULL occupied tinyint(4) NO NULL image char(12) NO MUL NULL pos tinyint(3) NO MUL NULL
我不得不说 wdata.id 和 odata.vref 已经编入索引!
表结构->
CREATE TABLE IF NOT EXISTS `odata` ( `vref` int(10) unsigned NOT NULL, `type` tinyint(4) NOT NULL, `conqured` mediumint(8) unsigned NOT NULL, `wood` float(12,2) NOT NULL, `iron` float(12,2) NOT NULL, `clay` float(12,2) NOT NULL, `woodp` float(12,2) NOT NULL, `ironp` float(12,2) NOT NULL, `clayp` float(12,2) NOT NULL, `maxstore` mediumint(8) unsigned NOT NULL, `crop` float(12,2) NOT NULL, `cropp` float(12,2) NOT NULL, `maxcrop` mediumint(8) unsigned NOT NULL, `lasttrain` int(10) unsigned NOT NULL, `lastfarmed` int(10) unsigned NOT NULL, `lastupdated` int(10) unsigned NOT NULL, `loyalty` tinyint(4) NOT NULL DEFAULT '100', `owner` smallint(5) unsigned NOT NULL DEFAULT '2', `name` char(45) NOT NULL DEFAULT 'Unoccupied Oasis', PRIMARY KEY (`vref`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
对于 wdata 来说是 ->
CREATE TABLE IF NOT EXISTS `wdata` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `fieldtype` tinyint(3) NOT NULL, `oasistype` tinyint(3) NOT NULL, `x` smallint(5) NOT NULL, `y` smallint(5) NOT NULL, `occupied` tinyint(4) NOT NULL, `image` char(12) NOT NULL, `pos` tinyint(3) NOT NULL, PRIMARY KEY (`id`), KEY `x` (`x`), KEY `y` (`y`), KEY `image` (`image`), KEY `pos` (`pos`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=160802 ;
致以诚挚的问候。
最佳答案
目前没有任何索引可以加快查询速度。目前,它必须对两个表JOINing
结果中的每一行计算SQRT
。
通过在执行任何JOINing
之前找到关闭30,您将获得一些改进:
SELECT *, distance
FROM ( SELECT id,
(ROUND(SQRT(
POW(LEAST(ABS(-12 - wdata.x),
ABS(401 - ABS(-12 - wdata.x))), 2) +
POW(LEAST(ABS(45 - wdata.y),
ABS(401 - ABS(45 - wdata.y))), 2)),3)
) AS distance
FROM wdata
HAVING distance<4.9497474683058326708059105347339
ORDER BY distance
LIMIT 30
) w
JOIN odata ON w.id=odata.vref
ORDER BY w.distance
这将需要 id 和 vref 建立索引。
下一项改进是将搜索限制在至少一个方向:
AND x >= -12 - 4.94...
AND x <= -12 + 4.94...
并且在wdata
中具有复合索引INDEX(x, id)
。 (抱歉,我不知道“401”在公式中的位置。)
如果这还不够快,则解决方案为 more complicated .
关于MySQL - 如何索引该查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33713747/