【问题标题】:MySQL chooses to execute queries, or not, at whimMySQL 随心所欲地选择执行或不执行查询
【发布时间】:2018-08-14 18:45:08
【问题描述】:

对于报告输出,我曾经删除并重新创建表“mis.pr_approval_time”。但现在我只是截断它。

用数据填充上表后,我运行了一个 UPDATE 语句,但我已将其写为下面的 SELECT...

SELECT t.account_id FROM mis.hj_approval_survey h INNER JOIN mis.pr_approval_time t ON h.country = t.country AND t.scheduled_at =
(
    SELECT MAX(scheduled_at) FROM mis.pr_approval_time 
    WHERE country = h.country 
    AND scheduled_at <= h.created_at 
    AND TIME_TO_SEC(TIMEDIFF(h.created_at, scheduled_at)) < 91
);

当我运行上述语句甚至只是......

SELECT t.account_id FROM mis.hj_approval_survey h INNER JOIN mis.pr_approval_time t ON h.country = t.country AND t.scheduled_at =
(
    SELECT MAX(scheduled_at) FROM mis.pr_approval_time 
    WHERE country = h.country
);

...它永远运行,似乎没有完成。 hj_approval_survey 表中只有约 3,400 行,pr_approval_time 中只有 29,000 行。我在具有 15+ GB RAM 的 Amazon AWS 实例上运行它。

现在,如果我只是右键单击 pr_approval_time 表并选择 ALTER TABLE 选项,然后不做任何事情直接关闭,那么上述查询将在几秒钟内运行。

我想当我触发 ALTER TABLE 选项并且 Workbench 填充表字段时,它可能会以某种方式改进其执行计划,但我不知道为什么。有没有人遇到过类似的情况?如何在不右键单击表并选择“ALTER TABLE”的情况下触发更好的执行计划检查

编辑

值得一提的是,我的组织也使用 DOMO。最初,我在 DOMO 上将此设置作为 MySQL 数据流,但在大多数情况下查询不会完成,但我观察到它有时会完成。

这就是我将此查询移回我们的 AWS MySQL RDS 的原因。所以这个问题不仅在我们自己的 MySQL RDS 上观察到,而且可能在 DOMO 上也观察到了

【问题讨论】:

  • 您是否索引了 WHERE 子句中涉及的列?这将是最简单的性能调优步骤。
  • @Littlefoot 是的,两个表都创建了索引列并显示在查询计划(解释)中。当我在那里看到它时,它显示为绿色框,但查询没有完成。此外,正如我在上面提到的,即使没有索引列,30,000 行也算不了什么

标签: mysql sql mysql-workbench sql-execution-plan


【解决方案1】:

我怀疑这很慢,因为相关的子查询(子查询取决于父表中的行值,这意味着它必须为每一行执行)。我会尝试稍微修改 pr_approval_time 表,使其成为时间点,然后您可以使用 JOIN 来选择正确的行,而无需执行相关的子查询。比如:

SELECT
    hj_approval_survey.country
,   hj_approval_survey.created_at
,   pr_approval_time.account_id
FROM
    @hj_approval_survey AS hj_approval_survey
JOIN    (
            SELECT
                current_row.country
            ,   current_row.scheduled_at AS scheduled_at_start
            ,   COALESCE( MIN( next_row.scheduled_at ), GETDATE() ) AS scheduled_at_end
            FROM
                @pr_approval_time AS current_row
            LEFT OUTER JOIN
                @pr_approval_time AS next_row ON (
                    next_row.country = current_row.country
                AND next_row.scheduled_at > current_row.scheduled_at
                )
            GROUP BY
                current_row.country
            ,   current_row.scheduled_at
        ) AS pr_approval_pit ON (
            pr_approval_pit.country = hj_approval_survey.country
        AND (   hj_approval_survey.created_at >= pr_approval_pit.scheduled_at_start
            AND hj_approval_survey.created_at < pr_approval_pit.scheduled_at_end
            )
        )
JOIN    @pr_approval_time AS pr_approval_time ON (
            pr_approval_time.country = pr_approval_pit.country
        AND pr_approval_time.scheduled_at = pr_approval_pit.scheduled_at_start
        )
WHERE
        TIME_TO_SEC( TIMEDIFF( hj_approval_survey.created_at, pr_approval_time.scheduled_at ) ) < 91

【讨论】:

  • 我不得不稍微更改一下您的查询,但它工作正常。不知道为什么。
【解决方案2】:

假设您对连接所涉及的列有正确的索引 您可以尝试使用按子查询分组并加入国家/地区来重构您的查询

  SELECT t.account_id 
  FROM mis.hj_approval_survey h 
  INNER JOIN mis.pr_approval_time t ON h.country = t.country 
  INNER JOIN (
    SELECT country, MAX(scheduled_at)  max_sched
        FROM mis.pr_approval_time 
        group by country
    ) z on z.contry = t.country and t.scheduled_at = z.max_sched

【讨论】:

  • 不确定您是否理解我试图做的事情,但批准时间和调查创建时间之间并不完全匹配。因此,我使用子查询来获得最接近调查创建的批准时间。先进行审批,然后再创建调查。
  • 如果你展示了一个正确的数据样本和预期的结果......更容易理解你想要做什么......
猜你喜欢
  • 2020-07-31
  • 1970-01-01
  • 2018-05-17
  • 1970-01-01
  • 2017-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多