MySQL 抱怨 max_allowed_pa​​cket 违规,查询短于允许的限制

Posted

技术标签:

【中文标题】MySQL 抱怨 max_allowed_pa​​cket 违规,查询短于允许的限制【英文标题】:MySQL complains about max_allowed_packet violation with query shorter than the allowed limit 【发布时间】:2021-11-16 05:14:14 【问题描述】:

执行多插入查询时,我收到错误“SQLSTATE[08S01]: Communication link failure: 1153 Got a packet greater than 'max_allowed_pa​​cket' bytes”。我有一个复杂的类,它组成了多插入查询,彻底检查了限制,所以这真的很奇怪,但是,我们都是人类,所以在尝试找到问题后,我刚刚捕获并记录了异常详细信息并且可以不明白发生了什么。代码(php 7.4、PDO、MariaDB 10.5.10):

        $this->pdoInstance = sql_get_connect($this->connection);

        $stmt = $this->pdoInstance->query("show variables like 'max_allowed_packet'");
        $d = sql_fetch($stmt);
        $stmt->closeCursor();
        $this->max_size = (int) $d['Value'];
...
        try 
            $stmt = $this->pdoInstance->query($query);
         catch (CDbException $e) 
            if (strpos($e->getMessage(), 'max_allowed_packet') !== false) 
                log ([
                    'total_size' => strlen($query),
                    'max_size' => $this->max_size,
                ];
            
            throw $e;
        

我得到的是:

total_size => 33554425
max_size => 33554432

所以我发送的查询实际上比限制少了 7 个字节。但是问题被稳定地重现了。是什么原因造成的?可能有一些标题与查询或任何东西一起发送,但我如何确定它们的大小?我在 mysql 和 MariaDB 文档中都没有找到任何关于它的信息。

【问题讨论】:

忽略语言,does the answers to this question help?。似乎与其说是程序问题,不如说是网络问题。 我会假设数据包有超过 7 个字节的开销。 谢谢你的想法,@Jaquarh,但我不这么认为。我收到的错误消息指定错误代码 1153 并提到超过 max_allowed_pa​​cket 字节长度。此外,它是一个每秒有大量查询的生产系统,并且在 99.99% 的时间内一切正常;多说一句,我正在运行的脚本也可以正常工作 --- 有一段时间了,并且仅在使查询非常接近限制的某些特定数据集上失败。 我可能会假装 max_size 比实际限制低一点,比如 (int) $d['Value'] - 256 或 (int) ($d['Value'] * 0.9),这将起作用。但我想了解问题的原因:为什么真正的限制与 max_allowed_pa​​cket 不同?有什么区别,差值取决于什么?这就是为什么我问我的问题,希望有人已经解决了它并可以回答它。 【参考方案1】:

strlen() 没有正确处理多字节字符,因为它假定 1 个字符等于 1 个字节,这对于 unicode 根本无效。

尝试改用mb_strlen()函数(mb代表多字节)。

【讨论】:

我知道 strlen() 不能正确处理 MB 字符,但它的问题是它计算字节而不是字符,而不是你说的相反。如果你想计算字符,你必须使用 mb_strlen(),但我确实需要字节。见3v4l.org/KZuHo 您是否尝试过指定编码? $bytes = mb_strlen($a, '8bit'); 这是可能的,当然 :) 但没有必要,因为 strlen() 以字节为单位计算字符串的大小,完全符合我的需要。好吧,(1)查询中根本没有多字节字符,(2)我已经捕获了我遇到问题的查询,将它保存到一个文件中,它的大小正好是 33554425,所以它是正确的值。 好的,那么如果 1) 你增加了 max_allowed_pa​​cket 的限制会发生什么?什么值是可以接受的?关键是计算我们丢失了多少字节,确切地说是 7 或更多? 2)如果您将查询保存在 mysql 行中,并从该单元格中读取,我们得到什么大小? 我负担不起仅仅为了测试而重新配置生产数据库,但我做了一些其他测试。 1)当我将查询保存到文件并通过mysql控制台客户端执行时,它工作正常;如果我在查询数据中再添加 5 个字节,它仍然可以工作,并且当我更改任何部分而整体大小保持不变时——它也可以工作,所以真正的查询限制总是比 max_allowed_pa​​cked 少 2 个字节。这是有道理的,因为在字符串的末尾应该有查询大小或类似零字符的东西。【参考方案2】:

嗯,问题看起来很简单。我们的应用服务器上安装了一个 PHP 扩展,它会干扰 PDO 查询的执行,并在那里添加特殊的 cmets。它是复杂入侵检测系统或类似系统的一部分,但从未记录过它会影响查询长度;现在我知道了。

抱歉打扰,感谢大家的帮助!

【讨论】:

以上是关于MySQL 抱怨 max_allowed_pa​​cket 违规,查询短于允许的限制的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 错误 1153 - 收到的数据包大于“max_allowed_pa​​cket”字节

MySQL 错误 1153 - 收到的数据包大于“max_allowed_pa​​cket”字节

如何更改 max_allowed_pa​​cket 大小

在 AWS RDS 上托管的数据库上导入 SQL 脚本期间出现 MySql 错误“max_allowed_pa​​cket”字节

SET GLOBAL max_allowed_pa​​cket 不起作用[重复]

导入大型 sql 文件时 MySQL 服务器已消失