答案 0 :(得分:1)
使用GROUP BY
代替
SELECT my_robots.*,
count(id) as openorders,
apikeys.apikey,
apikeys.apisecret
FROM my_robots
JOIN apikeys ON apikeys.id = my_robots.idApiKey
LEFT JOIN hpsi_trading ON hpsi_trading.idRobot = my_robots.id and estado <= 1
WHERE estado <= 1 and
idRobot = '2' and
ready = '1' and
(
my_robots.id LIKE '%0' OR
my_robots.id LIKE '%1' OR
my_robots.id LIKE '%2'
)
GROUP BY my_robots.id, apikeys.apikey, apikeys.apisecret
使用显式JOIN
语法。需要一些索引来快速运行它,但是,您的帖子(以及您的查询)中的数据库结构也不清楚。
答案 1 :(得分:0)
解释计划显示最大的痛苦是从表 hpsi_trading 中选择数据。
从数据库的角度来看,挑战是查询在SELECT子句中包含一个相关的子查询,需要对外部查询的每个结果执行一次(在过滤之后)。
使用JOIN + GROUP BY替换此子查询将需要MySQL在所有这些记录之间加入(膨胀),然后才使用GROUP BY对数据进行收缩,这可能需要一些时间。
相反,我会将子查询提取到临时表,该表在创建期间分组,索引并加入它。这样,子查询将运行一次,使用快速覆盖索引,它将已经对数据进行分组,然后将其连接到另一个表。
到目前为止,它是所有专业人士。但是,这里的问题是将子查询提取到临时表可能需要在开发方面付出更多努力。
请尝试使用此版本并告知我们是否有帮助(如果没有,请提供新的EXPLAIN计划截图):
创建临时表:
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS
SELECT idRobot, COUNT(id) as openorders
FROM hpsi_trading
WHERE estado <= 1
GROUP BY idRobot;
修改后的查询:
SELECT
my_robots.*,
temp1.openorders,
apikeys.apikey,
apikeys.apisecret
FROM
my_robots,
apikeys
LEFT JOIN temp1 on temp1.idRobot = my_robots.id
WHERE
estado <= 1 AND idRobot = '2'
AND ready = '1'
AND apikeys.id = my_robots.idApiKey
AND (my_robots.id LIKE '%0'
OR my_robots.id LIKE '%1'
OR my_robots.id LIKE '%2')
为此解决方案添加的索引(我从逻辑中假设 estado , idRobot 和 ready 来自apikeys表。如果那样& #39;不是这样,让我知道,我会调整索引):
ALTER TABLE `temp1` ADD INDEX `temp1_index_1` (idRobot);
ALTER TABLE `hpsi_trading` ADD INDEX `hpsi_trading_index_1` (idRobot, estado, id);
ALTER TABLE `apikeys` ADD INDEX `apikeys_index_1` (`idRobot`, `ready`, `id`, `estado`);
ALTER TABLE `my_robots` ADD INDEX `my_robots_index_1` (`idApiKey`);