BigQuery PHP API - большой объем памяти результатов запроса - даже с подкачкой - PullRequest
0 голосов
/ 07 сентября 2018

Я выполняю ряд запросов в BigQuery и экспортирую их в CSV через PHP. Есть причины, по которым это самый простой способ сделать это (несколько запросов, зависящих от переменных в приложении).

У меня проблемы с памятью, когда набор результатов больше 100 МБ. Похоже, что использование памяти моего кода, кажется, растет в соответствии с результирующим набором, который, я думал, можно было бы избежать с помощью подкачки страниц. Вот мой код:

$query = $bq->query($myQuery);
$queryResults = $bq->runQuery($query,['maxResults'=>5000]);

$FH = fopen($storagepath, 'w');

$rows = $queryResults->rows();

foreach ($rows as $row) {
    fputcsv($FH, $row);
}

fclose($FH);

Функция $queryResults->rows() возвращает Google Iterator, который использует подкачку для прокрутки результатов, поэтому я не понимаю, почему использование памяти увеличивается при выполнении сценария.

Мне не хватает способа удалить предыдущие страницы из памяти при просмотре результатов?

UPDATE

Я заметил, что фактически после обновления до PHP API BigQuery v1.4.3 использование памяти для этого процесса достигает 120 МБ, даже когда результирующий набор выходит далеко за пределы этого (в настоящее время обрабатывается набор результатов в 1 ГБ). Но все же 120 Мб кажется слишком большим. Как я могу определить и исправить, где эта память используется?

ОБНОВЛЕНИЕ 2 Эти 120 МБ, кажется, связаны на 24 КБ за maxResult на странице. Например. добавление 1000 строк к maxResults добавляет 24 МБ памяти. Итак, мой вопрос теперь , почему 1 строка данных использует 24 КБ в Google Iterator? Есть ли способ уменьшить это? Сами данные составляют <1 КБ на строку. </strong>

1 Ответ

0 голосов
/ 09 сентября 2018

Отвечая на мой вопрос

Дополнительная память используется загрузкой отображения типов PHP и другой информацией о структуре данных, которая поставляется вместе с данными из BigQuery. К сожалению, я не смог найти способ уменьшить использование памяти ниже примерно 24 КБ на строку, умноженное на размер страницы. Если кто-то найдет способ уменьшить раздувание, сопровождающее данные, пожалуйста, напишите ниже .

Однако благодаря одному из комментариев я понял, что вы можете извлечь запрос непосредственно в CSV в Google Cloud Storage Bucket. Это действительно легко:

query = $bq->query($myQuery);

$queryResults = $bq->runQuery($query);

$qJobInfo = $queryResults->job()->info();

$dataset = $bq->dataset($qJobInfo['configuration']['query']['destinationTable']['datasetId']);

$table = $dataset->table($qJobInfo['configuration']['query']['destinationTable']['tableId']);

$extractJob = $table->extract('gs://mybucket/'.$filename.'.csv');

$table->runJob($extractJob);

Однако это все еще не решило мою проблему, так как мой набор результатов был больше 1 ГБ, поэтому мне пришлось использовать функцию разделения данных, добавив подстановочный знак.

$extractJob = $table->extract('gs://mybucket/'.$filename.'*.csv');

Это создало ~ 100 осколков в ведре. Они должны быть перекомпонованы с использованием gsutil compose <shard filenames> <final filename>. Однако gsutil позволяет создавать только 32 файла одновременно. Учитывая, что у меня будет переменное число шардов, как правило, выше 32, мне пришлось написать некоторый код для их очистки.

//Save above job as variable
$eJob = $table->runJob($extractJob);

$eJobInfo = $eJob->info();

//This bit of info from the job tells you how many shards were created
$eJobFiles = $eJobInfo['statistics']['extract']['destinationUriFileCounts'][0];

$composedFiles = 0; $composeLength = 0; $subfile = 0; $fileString = "";

while (($composedFiles < $eJobFiles) && ($eJobFiles>1)) {

    while (($composeLength < 32) && ($composedFiles < $eJobFiles)) {
        // gsutil creates shards with a 12 digit number after the filename, so build a string of 32 such filenames at a time                            
        $fileString .= "gs://bucket/$filename" . str_pad($composedFiles,12,"0",STR_PAD_LEFT) . ".csv ";

        $composedFiles++;

        $composeLength++;

    }

    $composeLength = 0;

    // Compose a batch of 32 into a subfile
    system("gsutil compose $fileString gs://bucket/".$filename."-".$subfile.".csv");

    $subfile++;

    $fileString="";
}

if ($eJobFiles > 1) {
    //Compose all the subfiles                        
    system('gsutil compose gs://bucket/'.$filename.'-* gs://fm-sparkbeyond/YouTube_1_0/' . $filepath . '.gz') ==$
}

Примечание. Чтобы предоставить моему пользователю Apache доступ к gsutil, мне пришлось разрешить пользователю создавать каталог .config в корневом веб-каталоге. В идеале вы должны использовать PHP-библиотеку gsutil, но я не хотел, чтобы код раздувался.

Если у кого-то есть лучший ответ, пожалуйста, напишите его

  1. Есть ли способ получить меньший вывод из библиотеки BigQuery, чем 24 КБ на строку?

  2. Есть ли более эффективный способ очистки переменного количества осколков?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...