我在索引此查询时遇到问题:
#include <iostream>
#include <math.h>
using namespace std;
class Valjak{
private: float r, h;
public:
Valjak(){
r = 1;
h = 1;
}
Valjak(float rr, float hh){
r = rr;
h = hh;
}
void Oplosje(){
cout << "Oplosje valjka je: " << 2 * (pow(r, 2)*3.14) + 2 * r*h << endl;
}
void Volumen(){
cout << "Volumen je: " << (pow(r, 2)*3.14) * h << endl;
}
};
int main(){
Valjak V1;
Valjak V2(5, 10);
cout << "Vrijednosti prvog objekta!" << endl;
V1.Oplosje();
V1.Volumen();
cout << "Vrijednosti drugog objekta" << endl;
V2.Oplosje();
V2.Volumen();
system("PAUSE");
return 0;
}
结果是:
+----+-------------+-------+--------+---------------+---------+---------+-----------------------------+-------+---------------------------------+ | 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已经编入索引了!
表格结构 - &gt;
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是 - &gt;
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 ;最好的问候。
答案 0 :(得分:1)
没有索引可以加快查询的速度。它目前必须为SQRT
两个表的结果中的每一行评估JOINing
。
通过在执行任何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...
并在INDEX(x, id)
中包含复合索引wdata
。 (对不起,我不知道“401”在哪里符合公式。)
如果速度不够快,解决方案将获得more complicated。
答案 1 :(得分:1)
就像Rick James所说,你不能索引distance
,因为它是动态计算的。
这给你两个问题:1,它很慢,如你所知。 2,你在数据层做了逻辑计算,我不喜欢这个。
我认为这里最好的解决方案是不在你做的时候即时计算距离。为什么不在插入/更新wdata
和/或x
的同时将距离存储在y
?将其放在名为distance
的列中。然后你可以索引该列,一切都会非常快。此外,您不会再次重复计算,使事情更有效率。最后,您将能够删除数据层的计算并将其放入应用程序级别更合适的位置。
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,
`distance` decimal(32, 24) 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 `distance` (`distance`),
KEY `image` (`image`),
KEY `pos` (`pos`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=160802;
(距离的数据类型可以是您认为合适的任何内容。我使用decimal(32, 24)
来存储小数点右边最多24个位置的数字,最多存储12个左边的数字。根据需要调整。)
然后你可以将插入更改为:
(样本数据:
)
insert into wdata (fieldtype,oasistype,x,y,distance,occupied, image, pos)
values (1, 1, 10, 11, (ROUND(SQRT(
POW(LEAST(ABS(-12 - 10),
ABS(401 - ABS(-12 - 10))), 2) +
POW(LEAST(ABS(45 - 11),
ABS(401 - ABS(45 - 11))), 2)),3)
), 1, 'abcdefghijkl', 1)
并且您的select语句将是:
SELECT * FROM odata
LEFT JOIN wdata ON wdata.id=odata.vref
where wdata.distance<4.9497474683058326708059105347339
ORDER BY wdata.distance
LIMIT 30
如果你已经在wdata表中有一堆数据并且你不能新添加它,你可以这样做一次更新所有行(在你为距离添加新列之后):
update wdata set distance =
(ROUND(SQRT(
POW(LEAST(ABS(-12 - x),
ABS(401 - ABS(-12 - x))), 2) +
POW(LEAST(ABS(45 - y),
ABS(401 - ABS(45 - y))), 2)),3))
还值得注意的是,我会从MySQL中删除数学并让你的应用程序执行此操作。
例如,在PHP中:
$distance = (round(sqrt(pow(min(abs(-12 - 10), abs(401 - abs(-12 - 10))), 2) + pow(min(abs(45 - 11), abs(401 - abs(45 - 11))), 2)),3));
$sql = "insert into wdata (fieldtype, oasistype, x, y, distance, occupied, image, pos)
values (1, 1, 10, 11, $distance, 1, 'abcdefghijkl', 1)";