繁体   English   中英

MySQL 使用临时表进行查询优化

[英]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 服务器中运行良好,我假设是因为我不需要为UPDATEJOIN本身制作 160 万行的临时表的 3 个副本。 此查询在 MySQL 中运行极其缓慢。 关于如何优化它以更有效地运行的任何建议? 我在 MySQL 服务器 5.7.30 上运行

编辑最后,在UPDATE之后还有另一个查询,它缩小了 SELECT 的SELECTJOIN是另一个表并使用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'格式表示日期。

我使用这种方法是因为这些是JOINWHEREGROUP BY子句中的常见列。 我偶然发现了这个,无论是复合索引还是覆盖索引,读取 SO 和this的方法。

我在我创建的每个临时表上创建了索引,因为我不确定索引是否从每个表中继承。 当我尝试仅在table_1上执行此操作时,它仍然很慢,因此我在每次创建时都保留了它们。

编辑经过测试,我只需要为table_1table_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM