【问题标题】:Monitor the output file while running the long MySQL query into that output file在对输出文件运行长 MySQL 查询时监视输出文件
【发布时间】:2020-01-11 23:24:15
【问题描述】:

所以我有很长时间运行 MySQL 查询:Optimise comparing data in two big MySQL tables

显然有结果:中断查询后发现输出文件确实被修改了,有几千条记录。但是在我中断长时间运行的查询时,结果被刷新到文件中

我用过命令:

mysql> SELECT ar.email FROM activation_request ar WHERE ar.date_confirmed is not null AND NOT EXISTS (SELECT 1 FROM user u WHERE u.username = ar.email) INTO OUTFILE '/tmp/results_after_adding_indexes.csv';

如何同时监控/开球?该文件是在文件系统中创建的,但它是空的(直到查询结束或中断;无论先发生什么)。

【问题讨论】:

    标签: mysql monitoring query-performance


    【解决方案1】:

    一些查询是线性运行的。也就是说,它们以固定的速度产生另一行。

    有些查询在发出“第一”行之前就完成了 99% 的工作。如果查询有ORDER BY,这很容易看出。

    一些连接在将任何东西发送回客户端之前计算整个结果。一些连接会分块输出。

    连接问题可能是可以解决的。但是用排序之类的东西来“监控”一个查询是不切实际的。

    【讨论】:

    • 当然,但这次不是这样,对吧?我没有使用排序、排序,或者在收到正确的结果之前我不必计算整个数据集(因为在中断的情况下我不会得到任何结果)。不幸的是,您的回答似乎跑题了。
    • 但是,NOT EXIST 可能会长期返回 false,从而导致生成行之间的时间“很长”。
    • 那么您认为SELECT email FROM activation_request l LEFT JOIN user r ON r.username = l.email WHERE l.date_confirmed is not null AND r.username IS NULL 应该更快?
    • @Michal_Szulc - 很难说。两者都试试。
    • 我试过了:stackoverflow.com/questions/59669491/… 都需要很长时间才能完成,我无法监控结果。
    【解决方案2】:

    由于INTO OUTFILE 不支持options 用于分页输出,我相信您需要编写自己的导出脚本。

    (请注意,您还可以查看 LOAD DATA options 以确保完整性,按照 INTO OUTFILE 文档的说明,但唯一有希望的是 LINES 选项,它用于自定义行分隔符。)

    假设您不需要记录行上的数据库引擎选项,脚本很简单:

    1. 报告/导出查询的“全部给我”版本 - 除非您的数据集太大,在这种情况下,包括分页循环;
    2. 对结果进行循环以进行简单的转换;
    3. 将您的传出行存储在一个数组中,以将其发送到文件;
    4. 每隔 n 行将该队列写入文件;
    5. 并确保不要仅仅因为它们在最后一个块中不包含 n 行而丢弃记录集的最后位。

    【讨论】:

    • 我不想“给我全部”查询。我确实想一个一个地监控出现的结果,而不是将它们存储在某个地方(文件就可以了)
    • 当然。我进行了编辑,以使您的问题更清晰,更具体。底线是(我相信)您将编写一个脚本,即使它只是为您的导出查询的现有 SELECT 组件添加一个分页循环。
    • “自己的导出脚本”是什么意思?它如何应用于呈现的查询?你有任何(类似的)例子吗?
    • “自己的导出脚本”意味着您将不得不使用 node 或 php 之类的脚本语言(或适当的编程语言,如果您愿意)编写脚本。它与呈现的查询有关,因为当您需要比数据库引擎提供的更多功能时,您需要通过像客户端一样连接到数据库的脚本或程序自己提供这些功能。恐怕上面的大纲足以作为一个例子。如果您正在寻找完整的解决方案,我们深表歉意。如果您是,我强烈建议您发布您的架构并通常扩展问题。
    【解决方案3】:

    这是您的查询,对吗? PK 是id,对吗?

    SELECT  l.email 
        FROM activation_request l 
        LEFT JOIN user r ON r.username = l.email 
        WHERE l.date_confirmed is not null 
          AND r.username IS NULL
    

    使用一些应用程序代码,在id 上创建一个循环,一次可能有 10,000 个:

    SELECT  l.email 
        FROM activation_request l 
        LEFT JOIN user r ON r.username = l.email 
        WHERE l.date_confirmed is not null 
          AND r.username IS NULL
          AND l.id BETWEEN 1 AND 10000;   -- added
    

    时间;然后将最后一行更改为

          AND l.id BETWEEN 10001 AND 20000;
    

    等等

    这将:

    • 提供缺少用户的所需行列表,尽管是零碎的。
    • 在第一个块之后,您可以推断以推断出预期的总时间。
    • 在几个块之后,您可能会感觉到它的速度是否在变化。
    • 您可以将数据放在一起形成一个进度条。

    以上假设ids 是“密集”的;那就是没有删除id。如果有已删除的 id,则块将不会是一致的 10000 行(而是更少的行)。这可以通过使用SELECT id FROM .. WHERE id > $leftoff ORDER BY id .. LIMIT 10000,1 找出下一个端点来解决。

    关于分块的更多信息:http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks(注意:这涉及到删除。)

    如果你通过NOT EXISTS 方法做几个块,你可以感觉到哪个更快。注意:运行两次以避免缓存弄乱时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-15
      • 2010-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-17
      相关资源
      最近更新 更多