У меня есть экземпляр r3 EC2 с 122 ГБ ОЗУ, подключенный к экземпляру r3 RDS, также с 122 ГБ ОЗУ. Я подключен через PHP CLI, и большинство передач данных выполняются правильно.
Из-за массивной природы базы данных мне пришлось разбить данные на 700 таблиц. Я должен выполнить запрос и извлечь 86 991 строк * 3 765 столбцов из разных частей этих таблиц (все строки и целые числа), но у меня не хватает памяти на отметке 2 ГБ. Я храню все в массиве.
Вот ошибка, которую я получаю:
171/3765 complete xxx
172/3765 complete xxx
173/3765 complete xxx
174/3765 complete xxx
PHP Fatal error: Out of memory (allocated 1978662912) (tried to allocate 52 byt
es) in on line 151
PHP Stack trace:
PHP 1. {main}() :0
PHP 2. mysqli_fetch_array() :151
Fatal error: Out of memory (allocated 1978662912) (tried to allocate 52 bytes) i
n on line 151
Call Stack:
0.0004 137192 1. {main}() :0
267.8024 1976770240 2. mysqli_fetch_array() :151
Вот мой код:
//loop through each variables
$tqra3 = array();
$i = 1;
foreach($variableNames as &$vn){
$vn2 = addslashes($vn);
//look up location of variable
$tq1 = "SELECT `location` FROM `$variableLocationTable` WHERE `Variable Name` = \"{$vn2}\";";
$tqr1 = mysqli_query($db, $tq1);
//table query error checking
if($tqr1 === FALSE){
$tqe1 = "error1: \r\n" . mysqli_error($db) ."\r\n";
echo $tqe1;
exit();
}
//fetch location of attribute
$tqfa1 = mysqli_fetch_array($tqr1);
$location = $tqfa1[0];
//get needed attribute values
$tq3 = "SELECT `id`, `$vn2` FROM $location WHERE `id` IN $concatIDs ORDER BY `id` ASC;";
$tqr3 = mysqli_query($db, $tq3);
//table query error checking
if($tqr3 === FALSE){
$tqe3 = "error3: \r\n" . mysqli_error($db) ."\r\n";
echo $tqe3;
exit();
}
//insert select statement results into array
//ERROR LOCATION
while($row3 = mysqli_fetch_array($tqr3)){
$id = $row3[0];
$attributeMarker = $row3[1];
$tqra3[$id][$vn] = $attributeMarker;
}
//error checking
echo $i . "/" . $countVN . " complete " . $vn . " done" . "\r\n";
$i++;
}
Вот способы, которые я уже пробовал отлаживать:
я пробовал ini_set('memory_limit', -1)
(..Я знаю, что это плохо, но я просто тестирую)
Я пытался установить memory_limit = 100000M
, Когда я делаю ini_get('memory_limit')
возвращает значение, установленное в php.ini
Я подумал, что, возможно, моя структура данных была проблемой, поэтому я попробовал фиксированный массив, но он вызвал ту же ошибку в 176/3765.
Я пробовал небуферизованные запросы, но так как я храню все в памяти, прежде чем записать его в CSV, похоже, он мало что делает.
Я перепутался с настройками параметров БД в экземпляре RDS на случай, если были некоторые ограничения, которых я достиг с этой стороны, но это тоже не помогло. Я специально пытался увеличить максимальный размер пакета, размер кэша и размер пула буферов.
Я дал PHP CLI привилегии в реальном времени через диспетчер задач на случай, если это может помочь, но это не помогло.
Я временно сделал обходной путь, при котором для каждой строки каждый столбец просматривается, а затем записывается в CSV-файл, чтобы практически ничего не хранить в памяти, но это экспоненциально увеличивает время выполнения и является слишком медленным.
Вот подсказки, которые мне нужны:
Я вполне уверен, что экземпляр EC2 имеет возможность хранить все это в памяти, но он определенно не должен исчерпывать память около отметки 2 ГБ. Я думаю, что есть кое-что, что мне нужно в моем конфигурационном файле, или мне нужно где-то настроить некоторые привилегии, но я сейчас врезался в стену
Задача ещё не решена.
Других решений пока нет …