[英]MySQL Query Optimization with Temporary Tables
编辑这些单独的查询是用于在 Excel 中构建报告的更大过程的一部分,该报告可以由其他用户自动刷新。
我正在将查询从 SQL 服务器转换为 MySQL。 下面的查询提取了大约 160 万条记录。
CREATE TEMPORARY TABLE table_1
AS
(SELECT...
FROM accounts a -- also a temporary table
JOIN tdate d ON a.date1 <= d.date2
WHERE PERIOD_DIFF(DATE_FORMAT(d.date2, '%Y%m'), DATE_FORMAT(a.date1, '%Y%m')) >= 0
);
然后它必须从自身更新并加入自身。 由于MySQL的限制,我需要将表复制两次。 UPDATE
是查询开始需要很长时间的地方。
/* Create duplicate temp tables */
CREATE TEMPORARY TABLE table_2
AS
(SELECT * FROM table_1);
CREATE TEMPORARY TABLE table_3
AS
(SELECT * FROM table_2);
/* UPDATE table_1 */
UPDATE table_1 a
JOIN
(SELECT ...
SUM(ind_costs) as tcosts
FROM table_2 b
JOIN table_3 s ON b.id = s.id
WHERE b.dperiod >= s.dperiod
GROUP BY b.id,
b.dperiod) z
ON a.id = z.id
AND a.dperiod = z.dperiod
SET a.tcosts = z.tcosts;
该查询在 SQL 服务器中运行良好,我假设是因为我不需要为UPDATE
和JOIN
本身制作 160 万行的临时表的 3 个副本。 此查询在 MySQL 中运行极其缓慢。 关于如何优化它以更有效地运行的任何建议? 我在 MySQL 服务器 5.7.30 上运行
编辑最后,在UPDATE
之后还有另一个查询,它缩小了 SELECT 的SELECT
, JOIN
是另一个表并使用WHERE
过滤。 这用于导出到 Excel 的报告中,并且可以由其他用户刷新。
DROP TEMPORARY TABLE IF EXISTS table_2;
DROP TEMPORARY TABLE IF EXISTS table_3;
-- The final query results from the procedure
SELECT ...
FROM table_1 a
JOIN stats s ON a.state = s.state
AND a.column1 = s.column1
AND a.column2 = s.column2
WHERE a.dperiod = DATE_FORMAT(NOW(),'%Y%m')
AND a.costs < s.avg_costs
ORDER BY period DESC;
该查询需要几秒钟才能在 SQL 服务器中运行,但我已经让它在 MySQL 中运行了一个多小时,但它仍然不完整。 我正在寻找任何可能加速整个过程的方法。 我意识到这有点模糊。 提前感谢您的建议。
解决方案编辑我发布了一个解决方案,可以将查询从一个多小时(我从不让它完成)加快到 4 分钟。 虽然并不完美,但这比我正在使用的要好得多。 如果人们有改进,我会接受其他建议,但是,我选择了目前对我有用的方法。
为什么你需要一个临时表呢? 只需运行一个查询。 我想你想要:
select t.*,
sum(ind_costs) over (partition by id order by dperiod) as running_ind_costs
from table_1 t1;
您可以将其包含在表的原始定义中。
虽然并不完美,但到目前为止,我所做的已经将查询从一个多小时(永远不会让它运行)减少到大约 4 分钟,在我指定的id
列和我的period
列上使用INDEX
。 我的id
列对个人来说是唯一的,并且 period 以'%Y%m'
格式表示日期。
我使用这种方法是因为这些是JOIN
、 WHERE
和GROUP BY
子句中的常见列。 我偶然发现了这个,无论是复合索引还是覆盖索引,读取 SO 和this的方法。
我在我创建的每个临时表上创建了索引,因为我不确定索引是否从每个表中继承。 当我尝试仅在table_1
上执行此操作时,它仍然很慢,因此我在每次创建时都保留了它们。
编辑经过测试,我只需要为table_1
和table_2
创建索引。 似乎索引已从table_2
复制到table_3
。
CREATE TEMPORARY TABLE table_1
AS
(SELECT...
FROM accounts a -- also a temporary table
JOIN tdate d ON a.date1 <= d.date2
WHERE PERIOD_DIFF(DATE_FORMAT(d.date2, '%Y%m'), DATE_FORMAT(a.date1, '%Y%m')) >= 0
);
/*
#############################################
added index here and for the first temp table
#############################################
*/
ALTER TABLE table_1
ADD INDEX (id, reporting_period);
/* Create duplicate temp tables */
CREATE TEMPORARY TABLE table_2
AS
(SELECT * FROM table_1);
-- additional index
ALTER TABLE table_2
ADD INDEX (placedetail_id, reporting_period);
CREATE TEMPORARY TABLE table_3
AS
(SELECT * FROM table_2);
/* UPDATE table_1 */
UPDATE table_1 a
JOIN
(SELECT ...
SUM(ind_costs) as tcosts
FROM table_2 b
JOIN table_3 s ON b.id = s.id
WHERE b.dperiod >= s.dperiod
GROUP BY b.id,
b.dperiod) z
ON a.id = z.id
AND a.dperiod = z.dperiod
SET a.tcosts = z.tcosts;
DROP TEMPORARY TABLE IF EXISTS table_2;
DROP TEMPORARY TABLE IF EXISTS table_3;
-- The final query results from the procedure
SELECT ...
FROM table_1 a
JOIN stats s ON a.state = s.state
AND a.column1 = s.column1
AND a.column2 = s.column2
WHERE a.dperiod = DATE_FORMAT(NOW(),'%Y%m')
AND a.costs < s.avg_costs
ORDER BY period DESC;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.