【问题标题】:Strange MySQL error "Empty row packet body" when using mysql_fetch_object (PHP 5.3.3)使用 mysql_fetch_object (PHP 5.3.3) 时出现奇怪的 MySQL 错误“Empty row packet body”
【发布时间】:2011-04-16 09:11:05
【问题描述】:

当我使用 PHP 从资源(查询)中获取行时,我遇到了一个非常奇怪、毫无意义且完全随机的错误。

我的开发机器是带有 Apache 2.2 的 Windows XP SP3,而 MySQL 在虚拟机上运行,​​使用 ubuntu 10.04,具有 768mb 内存、100GB 硬盘和 4 个逻辑内核(英特尔 q6600)。但是这个问题与 windows 上的 PHP 无关,因为我在数据库机器上运行代码时遇到了同样的错误。

我正在使用mysql 扩展(不是mysqlimysqlnd),但环顾四周,我找到了一个与mysqlnd 扩展相关的错误的补丁,所以我应该尝试一下。

主要问题是当我执行这个查询(一个非常大的查询,有几个派生表和超过 20 个连接)并快速处理结果并且一切顺利时,但是当我的代码花费大约 15/20 秒处理一个行块(我需要从它们之间以一种非常特殊的方式链接的行块构建一个对象,我不能改变这个,数据库不是我的,并从这个对象制作一些PDF)一段时间后(随机时间)我收到此错误“空行数据包正文”。

我使用无缓冲查询来减少内存消耗(如果我启用缓冲,我会得到大约 260MB 的已用内存)但这应该不是问题。

【问题讨论】:

  • 你能显示一些代码吗?您的命令超时设置为多少?
  • 问题与超时或内存限制无关,因为我已禁用第一个并将第二个设置为非常非常高的值
  • 在我工作的地方,我们也在 Windows XP Pro SP3 上使用本地 Apache 2.2/PHP 5.3.3 和共享测试数据库服务器进行开发,但我们一直收到此错误。但是,我不知道其版本的共享 Apache/Linux 设置不会给出此错误,因此这可能表明问题可能是由 Apache 版本或类似的东西引起的,而不是数据库配置或使用!
  • @DanieleSalvatoreAlbano 我有确切的问题。我累了很多东西。你最后解决了吗?
  • 错误信息相当笼统,问题本身是由网络连接中断触发的,这可能有多种不同的原因。您是否使用无缓冲查询?如果使用mysql客户端测试,查询是否需要很长时间才能执行?您很可能需要调整超时(如果 yiu 无法管理您正在使用的 mysql 实例,则全局在 mysql 或每个会话中)

标签: php mysql php-5.3


【解决方案1】:

实际的问题是 PHP 和 MySQL 之间的连接中断(=在所有数据被 PHP接收之前停止)。

当 PHP (PDO) 执行 MySQL 查询时,它会在打开的连接上发送查询,然后等待响应。响应由一组标头和一个正文组成,有点像 HTTP 请求。

如果在 PDO 没有收到所有 headers 时连接中断,那么您将收到警告“Error reading result set's header”,这意味着 PDO 无法解释响应,因为它只是部分(headers)。

如果在解析主体时连接断开,那么 PDO 将产生一个“空行数据包主体”,对应于您的错误。有关其他信息,请参阅this Github PR

所以解决方法是找出连接被终止的原因:

  • 是因为连接超时吗?然后尝试按照建议修复配置
  • 是因为连接被`KILLè 命令手动终止了吗?然后要求凶手停止这样做
  • 是不是因为 Mysql 内存已满而您的实例被您的虚拟主机杀死了?然后减小结果集大小/获得更大的 MySQL 服务器/请求更多 RAM
  • 是不是因为发生了“死锁”,所以 Mysql 任意终止了一个连接(MyISAM 表更可能发生,包括内部临时表)?然后尝试使用 InnoDB
  • 是不是因为硬件连接中断,比如 PHP 和 MySQL 之间的线路/wifi 接收不良?然后修复硬件。
  • 是因为转储程序要求终止所有连接以处理转储吗?然后等待现有连接完成,然后再运行转储

【讨论】:

  • 感谢您抽出宝贵的时间来回答,但该主题已经相当老了,9 年后即使您的分析/问题绝对有效,也会有很多事情发生变化 :)
  • @DanieleSalvatoreAlbano 实际上仍然是今天的问题,因为它与 MyISAM 无关(它也会发生在 InnoDB 上)所以是的,它可能对 OP 没有帮助,但知道原因是连接在发送身体数据时被杀死/关闭将帮助其他人从 Duckduckgo(或邪恶的搜索引擎:)登陆这里
  • 绝对,但这正是为什么在一个非常旧的线程中发帖不值得。登陆这个页面的人很可能会继续前进,因为如果,标题提到 PHP 5.3.3,帖子提到了 Windows XP 和 Apache 2.2 的使用,谢天谢地,为什么后者可能仍在使用前两个不再是了。
  • 这对我很有用。我正在对一些查询进行故障排除并终止了一个进程,以便不等待它结束长查询。后来我在错误日志中看到了这个通知,当时放不下。看完这个解释,一分钱掉了。
【解决方案2】:

我现在遇到了同样的问题,正在读取巨大的无缓冲查询。所有的表都是 InnoDB。

当另一个进程启动时它会停止mysqldump。所以这可能也是原因。

【讨论】:

    【解决方案3】:

    不久前出现此错误,我已通过增加

    的值来修复它
    net_read_timeout = 360
    net_write_timeout = 360
    

    当一个连接在写入时打开,等待另一个查询结束以继续插入,这会超时,给出一个空行数据包。我正在处理非常大的数据集,使用价值超过 360。您的价值将取决于您的用例。

    【讨论】:

    • 将这些行放在哪里,在哪个块中?
    • 在你的 mysql 配置中,通常称为 my.conf,在 mysqld 块中
    • 完美,我不确定是否有块。谢谢!
    【解决方案4】:

    我在 InnoDB 上,直到我切换编码环境(字面意思,就像位置)之前都没有遇到过这种类型的问题。因此,如果您更改了无线连接,则可能会出现问题,尤其是在公共场所时。

    【讨论】:

      【解决方案5】:

      我遇到了同样的错误,并且在更新同一个表的行时,我还在读取一个无缓冲的大型结果集。

      与其切换到 InnoDB,更好的解决方案可能是创建一个仅包含原始表主键的临时表。然后,遍历该临时表,同时从原始表中一次选择和更新一行。您必须使用两个单独的 MySQL 连接才能执行此操作,否则您将收到“命令不同步”错误。

      您可能需要锁定原始表,以防止其他人在发生这种情况时对其进行读取/写入。

      【讨论】:

        【解决方案6】:

        user589182 的回答很到位。我基本上在做同样的事情:读取一个无缓冲的大型结果集,并从同一个 PHP 脚本更新同一个表中的一些行。大约之后我收到了完全相同的错误消息。 2500 次更新。从 MyISAM 切换到 InnoDB 后问题解决了。

        【讨论】:

        • 好吧,我在 innodb 上,但如果我超压 mysql,我会收到错误。
        • @DanieleSalvatoreAlbano 我有确切的问题。我累了很多东西。你最后解决了吗?
        【解决方案7】:

        我遇到了同样的错误。我用的是PDO,不过应该基本一样吧。

        您是否在 MyISAM 表上进行操作?如果是这样,问题可能与此引擎使用的锁定模型有关:它锁定整个表,使用共享锁进行读取,使用排他锁进行写入。

        这就是我想要做的:读取一个无缓冲的大型结果集,并更新同一个表中的一些行。由于您不能在同一连接上发布一个未缓冲结果集的语句,因此我尝试使用另一个连接进行更新。阅读一直很顺利,直到第一次更新,此时脚本停止了大约一分钟,然后我得到了“空行数据包正文”错误。

        你看,当读取无缓冲时,共享锁会一直保持到整个结果集被读取或游标被关闭。在此期间,该表被共享锁锁定,因此其他连接可以获得该表上的共享锁(换句话说,从中读取),但排他锁(用于写入)将不得不等待。如果这发生在同一个脚本中,它将死锁。

        现在,为了防止无限死锁,MySQL 将在一段时间后强制释放您的共享锁(IIRC 这受 table_lock_wait_timeout 的值影响),转储您的结果集并允许等待排他锁的写入语句轮到它.

        因此,虽然在我的情况下是同一个脚本执行此操作并因此停滞到超时到期,但也可能是其他一些脚本正在尝试对表进行具有相同效果的写操作,这可能是发生在你身上。

        为我解决问题的方法是将表类型更改为 InnoDB,因为该引擎使用行级而不是表级锁。但是,既然您说数据库不是您的,那么您可能无法做到这一点。

        【讨论】:

        • 最初表类型是myisam,后来我切换到innodb进行测试,但问题仍然存在。但实际上我再也没有得到它,我必须对服务器施加过度压力才能得到它
        • 这对我不起作用,即使表格被复制并且我 100% 确定没有人写信给它。
        • 请注意,内部临时表(由 MySQL 为某些查询创建,请参阅 EXPLAIN)将在 MySQL 5.6 中使用 MyISAM:On-disk temporary tables are managed by the MyISAM storage engine 因此,您可能最终会遇到此错误,而查询似乎只涉及InnoDB 表(但实际上需要 MySQL 5.6 将使用 MyISAM 创建的临时表)
        猜你喜欢
        • 2011-09-17
        • 1970-01-01
        • 2020-08-30
        • 2013-05-05
        • 2012-05-05
        • 2011-06-16
        • 1970-01-01
        • 1970-01-01
        • 2018-10-14
        相关资源
        最近更新 更多