PHP массовое использование памяти для запроса SQL
Я наткнулся на странную проблему при оптимизации использования памяти Apache + PHP. В основном код взрывается с сообщением об ошибке "Неустранимая ошибка: допустимый объем памяти 16777216 байт исчерпан (попытка выделить 50331646 байт)" при попытке связать результаты запроса MySQLi.
Соответствующие таблицы:
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 на сервере работает нормально, а возвращаемый размер примечания составляет менее килобайта.
Одна странность в том, что размер, который он пытается выделить 50331646, равен 0x2FFFFFE в шестнадцатеричном формате, что является подозрительно круглым числом. Это похоже на то, что PHP пытается выделить буфер достаточно большой, чтобы вместить максимально возможное поле среднего текста, а не выделять память для извлеченных данных.
Кто-нибудь знает обходной путь для этого - кроме как увеличить максимальный объем памяти, разрешенный в PHP?
Кстати, другие люди имели такую же проблему, но, похоже, не знали, как ее решить. Недостаточно памяти (выделено 50855936) (попытался выделить 50331646 байт)
Точная линия, которая взрывается:
$statement->bind_result(
$content_contentID,
$content_text,
$content_datestamp,
$note_noteID,
$note_contentID,
$note_text);
Изменение запроса на выбор "" Тестовая строка "в качестве примечания" вместо выборки столбца больше не показывает массовое использование памяти.
Кстати, я уверен, что я не пытаюсь получить большие данные. Это показывает фактическую длину поля среднего текста в таблице примечаний:
select length(text) from basereality.note;
+--------------+
| length(text) |
+--------------+
| 938 |
| 141 |
| 1116 |
| 431 |
| 334 |
+--------------+
2 ответа
Я нашел ответ и прокомментировал еще один вопрос:
Допустимый объем памяти 67108864 байт исчерпан
По сути, в старой библиотеке коннекторов MySQL вместо того, чтобы просто выделять фактический размер поля 'text' для хранения результата, вместо этого выделяется максимально возможный размер типа mediumtext.
т.е. 16 мегабайт всегда выделяется, даже если поле для результата составляет всего 100 килобайт.
Самый простой и, вероятно, лучший способ исправить это - переключиться на использование нового коннектора MySQLND, который не показывает такое поведение.
Вы пробовали 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