5

在优化我的 Apache + PHP 内存使用时,我偶然发现了一个奇怪的问题。基本上,当尝试绑定 MySQLi 查询的结果时,代码会出现错误消息“致命错误:允许的内存大小为 16777216 字节已用尽(尝试分配 50331646 字节)”。

相关表格如下:

CREATE TABLE `note` (
  `noteID` int(11) NOT NULL AUTO_INCREMENT,
  `contentID` int(11) NOT NULL,
  `text` mediumtext NOT NULL,
  PRIMARY KEY (`noteID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `content` (
  `contentID` int(11) NOT NULL AUTO_INCREMENT,
  `text` varchar(2048) NOT NULL,
  `datestamp` datetime NOT NULL,
  PRIMARY KEY (`contentID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

爆炸的查询是:

select content.contentID, 
content.text, 
content.datestamp, 
note.noteID, 
note.contentID, note.text 
from basereality.content as content 
inner join basereality.note as note 
on content.contentID = note.contentID 
where content.contentID = 1028 ;

在服务器上的 MySQL 中运行查询运行良好,返回的“note”大小小于 1 KB。

一件奇怪的事情是它试图分配 50331646 的大小是 0x2FFFFFE 十六进制,这是一个可疑的整数。这几乎就像 PHP 试图分配一个足够大的缓冲区来容纳可能的最大的 mediumtext 字段,而不是实际为检索到的数据分配内存。

任何人都知道解决方法 - 除了增加 PHP 中允许的最大内存?

顺便说一句,其他人也有同样的问题,但似乎不知道如何解决。 内存不足(分配50855936)(尝试分配50331646字节)

爆炸的确切线路是:

$statement->bind_result(
  $content_contentID,
  $content_text,
  $content_datestamp,
  $note_noteID,
  $note_contentID,
  $note_text);

将查询更改为选择“'A test string' as note”,而不是获取列,不再显示大量内存使用情况。

顺便说一句,我确定我不是在尝试检索大数据。这显示了 note 表中 mediumtext 字段的实际长度:

 select length(text) from basereality.note;
+--------------+
| length(text) |
+--------------+
|          938 |
|          141 |
|         1116 |
|          431 |
|          334 |
+--------------+
4

2 回答 2

4

我找到了答案并在另一个问题中发表了评论:

67108864 字节的允许内存大小已用尽

基本上,在旧的 MySQL 连接器库中,不仅仅是分配字段“文本”的实际大小来存储结果,而是分配了 mediumtext 类型的最大可能大小。

即,即使结果字段只有 100 KB,也总是分配 16 兆字节。

解决此问题的最简单且可能最好的方法是切换到使用不显示此行为的新 MySQLND 连接器。

于 2012-11-21T00:21:15.733 回答
0

你试过mysqli_store_result吗?查看下面的 php.net 链接,更多人有同样的问题,有些人通过在绑定结果之前调用 store_result 解决了这个问题。

http://php.net/manual/en/mysqli.store-result.php

http://dev.mysql.com/doc/refman/5.0/en/mysql-stmt-store-result.html

于 2012-08-13T21:16:48.060 回答