Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

PHP mysql_stmt::fetch() dá a memória de erro fatal do PHP esgotada


Você descobrirá que isso está ocorrendo somente quando @status é NULL ou uma corda.

O problema é duplo:

  1. Ao contrário das variáveis ​​locais , MySQL variáveis ​​de usuário suportam um conjunto muito limitado de tipos de dados:

    A documentação não menciona que os tipos de dados reais usados ​​são respectivamente BIGINT , DECIMAL(65,30) , DOUBLE , LONGBLOB , LONGTEXT e LONGBLOB . Em relação ao último, o manual pelo menos explica:

    Armazenamento dos três primeiros desses tipos de dados (ou seja, para valores inteiros, decimais e de ponto flutuante) requerem 8, 30 e 8 bytes, respectivamente. Os outros tipos de dados (ou seja, para string e NULL valores) requerem (até) 4 gigabytes de armazenamento.

  2. Como você está usando uma versão do PHP anterior à v5.4.0, o driver padrão do MySQL é libmysql , com o qual apenas metadados do tipo coluna estão disponíveis no servidor na vinculação de dados - então o MySQLi tenta alocar memória suficiente para armazenar todos os valores possíveis (mesmo que o buffer completo não seja necessário); assim NULL - e variáveis ​​de usuário com valor de string, que têm um tamanho máximo possível de 4GiB, fazem com que o PHP exceda seu limite de memória padrão (de 128MiB desde o PHP v5.2.0).

Suas opções incluem:

  • Substituindo o tipo de dados da coluna na definição da tabela:
    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table (
      status VARCHAR(2)
    ) SELECT @status AS status;
    

  • Explicitamente transmissão a variável do usuário para um tipo de dados mais específico:
    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT CAST(@status AS CHAR(2)) AS status;
    

  • Usando variáveis ​​locais, que são declaradas com um tipo de dados explícito:
    DECLARE status VARCHAR(2) DEFAULT @status;
    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT status;
    

  • Resolvendo o problema chamando mysqli_stmt::store_result() antes mysqli_stmt::bind_result() , que faz com que o conjunto de resultados seja armazenado em libmysql (fora dos limites de memória do PHP) e então o PHP alocará apenas a memória real necessária para manter o registro ao buscá-lo:
    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result( $status );
    $stmt->fetch();
    

  • Aumentando o limite de memória do PHP para que ele possa acomodar a alocação de buffers de 4GiB (embora se deva estar ciente das implicações nos recursos de hardware de fazê-lo) - por exemplo, para remover completamente as restrições de memória (embora esteja ciente dos possíveis efeitos colaterais negativos de fazer isso, por exemplo, de vazamentos de memória genuínos):
    ini_set('memory_limit', '-1');
    

  • Recompilando o PHP, configurado para usar o driver mysqlnd nativo (incluído com PHP desde v5.3.0, mas não configurado como padrão até PHP v5.4.0) em vez de libmysql:
    ./configure --with-mysqli=mysqlnd
    

  • Atualizando para PHP v5.4.0 ou posterior para que o mysqlnd seja usado por padrão.