Laravel-datatables: Exportação do lado do servidor 200.000 registros

Criado em 31 mar. 2018  ·  19Comentários  ·  Fonte: yajra/laravel-datatables

Resumo do problema ou solicitação de recurso

Quando 200000 registra como exportar dados. Quando eu exporto os dados "Tamanho de memória permitido de 134217728 bytes esgotados", essa exceção é lançada.

Quais são as outras opções para exportar uma grande quantidade de dados em yajra / tabela de dados.

Forneça uma maneira diferente de exportar uma grande quantidade de dados.

Temos uma quantidade limitada de memória RAM no servidor.

Fragmento de código do problema

public function showData(ServiceDataTable $dataTable)
    {
        return $dataTable
            ->render('dataTable.renderDataTable');
    }

Detalhes do sistema

  • Sistema operacional: Ubuntu 16.04
  • Versão PHP: 7.0.0
  • Versão do Laravel: 5.5
  • Versão do Laravel-Datatables: 8.0
  • Botões Laravel-Datatables Versão: 3.1
performance question

Todos 19 comentários

Você precisa implementar seu próprio criador de arquivos do Excel para lidar com essa solicitação em massa. Em sua classe ServiceDataTable, você pode sobrescrever o método protected function buildExcelFile() e talvez fazer algumas partes, etc. Veja a documentação do laravel-excel para mais informações.

    /**
     * Build excel file and prepare for export.
     *
     * <strong i="7">@return</strong> \Maatwebsite\Excel\Writers\LaravelExcelWriter
     */
    protected function buildExcelFile()
    {
        /** <strong i="8">@var</strong> \Maatwebsite\Excel\Excel $excel */
        $excel = app('excel');

        return $excel->create($this->getFilename(), function (LaravelExcelWriter $excel) {
            $excel->sheet('exported-data', function (LaravelExcelWorksheet $sheet) {
                $sheet->fromArray($this->getDataForExport());
            });
        });
    }

Acho que Seguir código criando exceção
$this->getDataForExport();
Obtém uma exceção quando editColumn() lado do servidor é definido ou usado
existem 200.000 registros.
Existe alguma outra maneira de obter dados sem processar ou não alocar mais memória.
Eu tenho o seguinte link, mas yajra yajra / laravel-datatables-buttons: ^ 3.1 ainda não suporta Laravel / Excel: 3.0
https://laravel-excel.maatwebsite.nl/docs/3.0/export/queued

Deve haver uma forma que exporta diretamente da consulta ou forma eloqüente.

Eu uso o Postman para imitar essa operação, mas

Tamanho de memória permitido de 134217728 bytes esgotados

exceção lançada. Não tenho nenhuma linha que costumava gerar html, eu uso rawColumns () para escapar de html, minha consulta leva 0,420 ms no phpmyadmin e nos primeiros 1,4 segundos

Se formos capazes de colocá-lo na fila, devemos também poder salvá-lo em uma pasta no servidor e fornecer o link para o usuário fazer o download.

Agradecendo pela resposta.

Estou usando na tabela de dados JQuery ou yajra e desejo exportar do lado do servidor.

Acho que não é viável salvar em pasta no servidor, muitos problemas vão gerar problema.

Eu preciso de streaming de dados.

A quantidade de dados é de 20 MB em resposta ou maior.

Meu requisito é semelhante, mas gostaria de salvar o arquivo no servidor (ou S3) e fornecer um link para baixá-lo no painel do meu aplicativo ou e-mail. Estou vendo a possibilidade de fazer isso, se eu encontrar algo atualizarei aqui.

Tenho problemas com o processamento do lado do servidor, que consome grande quantidade de memória RAM e o tamanho de alocação de memória de script padrão é 60 MB.
Olhe para memory_limit em php.ini
O limite de tempo de execução max_execution_time é 60.
Depois de aumentar o valor, você foi capaz de fazer a solicitação usando a exportação do lado do servidor.

Modifiquei a função do excel para fazer armazenar o arquivo ao invés de baixar, ele está armazenando o arquivo em armazenamento / exportação / pasta.

public function excel()
{
    $this->buildExcelFile()->store('xls');
}

Atualmente, não estou tendo uma grande quantidade de dados em meu env de desenvolvimento. Você pode fazer as alterações acima em sua configuração e ver se é possível criar o excel nessa pasta sem atingir o limite de memória?

Outra coisa a notar é que estou usando o Laravel 5.1, portanto, maatwebsite / excel versão 2.1

O que eu realmente quero fazer é colocar isso na fila e retornar à página com uma mensagem de que a criação do relatório está em andamento e o link para baixar o arquivo será um e-mail para sua id registrada "

na versão 2.1 não tenho certeza de como fazer fila, mas descobri que eles usam " Queued Chunk ", mas não tenho certeza de como implementar isso.

Então, alguma atualização sobre isso?

Então, alguma atualização sobre isso?

Se alguém usar o Laravel Excel 3.0+ a solução superior não funcionará. então você deve substituir buildExcelFile() usando "Exportação em fila" .

Ou fiz outra coisa usando chunking também, mas criando meu traço e usando CSV para fazer meu trabalho e este é um exemplo

alguma atualização?

A partir do Laravel 6, você pode usar LazyCollections para carregar apenas um item por vez na memória. Isso corrige o problema de falta de memória.

Só precisa estender a classe DataTable e escrever um DataTablesExportHandler adaptado.

Confira minha essência

Aproveitar!

@singhofmarco Você pode dar um exemplo?

@singhofmarco Eu concordo, comecei um projeto v10 no ano passado que utilizará LazyCollections, mas não pode continuar atm.

Eu fui por um caminho diferente. Substituí a função csv, chamando DataTables com uma página de dados de cada vez, efetivamente fragmentando. Usando fputcsv nas linhas de resultado até que o arquivo esteja completo, então apenas retorne o conteúdo do arquivo em uma Resposta do Laravel.

Não apenas o limite de memória nunca é mais atingido (até que o próprio CSV cresça além do limite de memória do PHP, então uma resposta de streaming pode ajudar ainda mais), mas também é duas vezes mais rápido ......

@ameenross se possível, você pode compartilhar seu código, por favor.

@karmendra Eu prefiro não, pois é para uma versão mais antiga do Yajra Datatables. Mas basicamente o que estou fazendo é mesclar alguns valores de página e comprimento na solicitação, chamar o código que normalmente retorna uma página de dados para AJAX ( $this->ajax()->getData(true)['data'] no meu caso). Eu tenho uma classe base para datatables que estende a classe Yajra Datatable, com uma função getCsv (decidi não substituir a função CSV afinal, mas isso não é importante). Isso ocorre em um loop até que não haja mais páginas restantes.

@ameenross Obrigado, isso é útil. Vou tentar.

Laravel Datatable :: v1.5.0
Aqui está minha solução com base no comentário @TheGeekyM , deixo-a para o caso de ajudar alguém.
Eu criei uma classe ChunkedDatatableExportHandler que implementa FromQuery e, em seguida, substitui o método buildExcelFile em meu ServiceDataTables para usá-lo.

<?php

namespace App\DataTables;

use Yajra\DataTables\Services\DataTable;

class ServiceDataTable extends DataTable
{
  protected $exportClass = ChunkedDatatableExportHandler::class;

  protected function buildExcelFile()
  {
      $query = app()->call([$this, 'query']);
      $query = $this->applyScopes($query);

      $dataTable = app()->call([$this, 'dataTable'], compact('query'));
      $dataTable->skipPaging();
      $data_query = $dataTable->getFilteredQuery();

      return new $this->exportClass($data_query);
  }
}
<?php
namespace App\DataTables;

use Illuminate\Database\Query\Builder;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class ChunkedDatatableExportHandler implements FromQuery, WithHeadings
{
    use Exportable;

    /**
     * <strong i="11">@var</strong> Builder 
     */
    protected $query;

    /**
     * ChunkDatatablesExportHandler constructor.
     * <strong i="12">@param</strong> Builder $query
     */
    public function __construct(Builder $query)
    {
        $this->query = $query;
    }

    /**
     * <strong i="13">@return</strong> array
     */
    public function headings(): array
    {
        $first = $this->query()->first();

        if ($first) {
            return array_keys((array)$first);
        }

        return [];
    }

    /**
     * <strong i="14">@return</strong> Builder
     */
    public function query()
    {
        return $this->query;
    }
}
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

shadoWalker89 picture shadoWalker89  ·  3Comentários

t0n1zz picture t0n1zz  ·  3Comentários

ghost picture ghost  ·  3Comentários

hari-web picture hari-web  ·  3Comentários

nasirkhan picture nasirkhan  ·  3Comentários