MySQL长查询进度监控

KOG*_*OGI 49 mysql sql

只是为了提出我的问题,我明白没有直接支持这样的事情.我正在寻找的是任何类型的解决方案或复杂的推导,这将得到一个半可敬的结果.

我正在使用集群引擎处理一个相当大的MySQL集群(表> 4亿行).

是否有人知道通过mysql中的长查询直接检索或以其他方式获得某种(或更好)准确的进度指示的方法?我有一些查询可能需要长达45分钟,我需要通过处理确定我们是10%还是90%.

编辑:

根据评论中的要求,这是一个由我的原始问题引出的查询之一的精炼版本.

SELECT `userId`
FROM    `openEndedResponses` AS `oe`
WHERE
    `oe`.`questionId` = 3 -- zip code
    AND (REPLACE( REPLACE( `oe`.`value`, ' ', '' ), '-', '' ) IN ( '30071', '30106', '30122', '30134', '30135', '30168', '30180', '30185', '30187', '30317', '30004' ));
Run Code Online (Sandbox Code Playgroud)

此查询针对具有~9500万行的单个表运行.运行查询需要8秒,传输数据需要13秒(总共21秒).考虑到表的大小,以及使用字符串操作函数的事实,我会说它运行起来非常快.然而,对于用户来说,它仍然是21秒出现卡住或闲置.一些进展的迹象将是理想的.

小智 28

我知道这是一个老问题,但是当我试图弄清楚我的更新对250米行的查询需要多长时间时,我一直在寻找类似的答案.

如果您运行:

SHOW ENGINE INNODB STATUS \G
Run Code Online (Sandbox Code Playgroud)

然后在TRANSACTIONS下找到有问题的事务,检查这一部分:

---TRANSACTION 34282360, ACTIVE 71195 sec starting index read
mysql tables in use 2, locked 2
1985355 lock struct(s), heap size 203333840, 255691088 row lock(s), undo log entries 21355084
Run Code Online (Sandbox Code Playgroud)

重要的是"撤消日志条目".对于每个更新的行,在我的情况下,它似乎添加了一个撤消日志条目(尝试在几秒钟后再次运行它,看看已添加了多少).

如果您跳到状态报告的末尾,您会看到:

Number of rows inserted 606188224, updated 251615579, deleted 1667, read 54873415652
0.00 inserts/s, 1595.44 updates/s, 0.00 deletes/s, 3190.88 reads/s
Run Code Online (Sandbox Code Playgroud)

在这里我们可以看到正在应用的速度更新是每秒1595.44行(尽管如果你正在串联运行其他更新查询,那么这个速度可能会在你的查询之间分开).

所以,据此,我知道21米已经更新了(250m-21m)229m的行.

229,000,000/1600 = 143,125秒(143,125/60)/ 60 = 39.76小时

所以看起来我可以在另外几天扭动我的拇指.除非这个答案是错误的,在这种情况下我会在此之前的某个时间更新它!

  • 你的噪音对估计我的DELETE语句的运行时非常有用,所以非常感谢!似乎"行锁定"也是一个非常好看的数字,我怀疑它会告诉你到目前为止查询已查看了多少行(所有涉及的表),而"撤消日志"是它已改变了多少行. (3认同)

Dou*_*rch 7

我能够通过查询要处理的行数然后将处理分解为循环来估计这样的事情,一次只处理总行的子集.

整个循环相当复杂,但基本逻辑如下:

SELECT @minID = Min(keyColumn) FROM table WHERE condition
SELECT @maxID = Max(keyColumn) FROM table WHERE condition
SELECT @potentialRows = (@maxID - @minID) / @iterations

WHILE @minID < @maxID
BEGIN
    SET @breakID = @minID + @potentialRows
    SELECT columns FROM table WITH (NOLOCK, ...)
    WHERE condition AND keyColumn BETWEEN @minID AND @breakID

    SET @minID = @breakID + 1
END
Run Code Online (Sandbox Code Playgroud)

请注意,如果ID均匀分布,则此方法效果最佳


pgr*_*pgr 6

我在这里找到这个老问题的有希望的答案,由 Baron Schwartz 撰写。这不是一个精确和完整的解决方案,但它确实为估计提供了一些客观材料,如果您只运行该查询而您的服务器上没有其他任何内容

在查询已经运行时运行此命令:

mysqladmin extended -r -i 10 | grep Handler
Run Code Online (Sandbox Code Playgroud)
  • 10是命令重复的秒数,所以等待刷新
  • 添加类似的内容,-u root -p如果您需要进行身份验证
  • 如果您知道要查找的具体 Handler,则可以使 Handlergrep更加集中,例如Handler_read_rnd_next似乎对SELECT's有好处
  • 忽略第一个输出,使用第二个及以下
  • 用于Ctrl-C退出

现在得到那个数字并做你的数学运算。确定每秒处理的行数,并且根据您对表大小的了解,您可能能够对总时间进行相当精确的估计。

免费的额外提示:该命令似乎没有进入 Bash 历史记录(可能是因为退出了 with Ctrl-C,您可以手动将其添加到那里history -s mysqladmin extended -r -i 10 -u root -p | grep Handler

  • 这太棒了,应该是公认的答案。 (2认同)

KOG*_*OGI 2

目前,对于我的具体情况,似乎没有真正的解决方案。由于我无法将查询分成几个较小的查询,并且事实证明select count(*),首先运行“真正的”查询会适得其反(使本来就很慢的查询的执行时间加倍),所以所有解决方法似乎都不可行。也许很快,MySQL就会支持这样的东西