sql >> Base de Datos >  >> RDS >> Mysql

PHP mysql_stmt::fetch() da memoria de error fatal de PHP agotada

Encontrará que esto está ocurriendo solo cuando @status es NULL o una cadena.

El problema es doble:

  1. A diferencia de las variables locales , MySQL variables de usuario admite un conjunto muy limitado de tipos de datos:

    La documentación no menciona que los tipos de datos reales utilizados son respectivamente BIGINT , DECIMAL(65,30) , DOUBLE , LONGBLOB , LONGTEXT y LONGBLOB . Con respecto al último, el manual al menos explica:

    Almacenamiento de los tres primeros de estos tipos de datos (es decir, para valores enteros, decimales y de punto flotante) requieren 8, 30 y 8 bytes respectivamente. Los otros tipos de datos (es decir, para cadena y NULL valores) requieren (hasta) 4 gigabytes de almacenamiento.

  2. Dado que está utilizando una versión de PHP anterior a v5.4.0, el controlador MySQL predeterminado es libmysql , con el que solo los metadatos de tipo columna están disponibles desde el servidor en el enlace de datos, por lo que MySQLi intenta asignar suficiente memoria para contener todos los valores posibles (incluso si en última instancia no se requiere el búfer completo); por lo tanto NULL - y las variables de usuario con valores de cadena, que tienen un tamaño máximo posible de 4 GiB, hacen que PHP exceda su límite de memoria predeterminado (de 128 MiB desde PHP v5.2.0).

Sus opciones incluyen:

  • Anulando el tipo de datos de la columna en la definición de la tabla:

    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table (
      status VARCHAR(2)
    ) SELECT @status AS status;
    
  • Explícitamente casting la variable de usuario a un tipo de datos más específico:

    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT CAST(@status AS CHAR(2)) AS status;
    
  • Usando variables locales, que se declaran con un tipo de datos explícito:

    DECLARE status VARCHAR(2) DEFAULT @status;
    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT status;
    
  • Solucione el problema llamando a mysqli_stmt::store_result() antes mysqli_stmt::bind_result() , lo que hace que el conjunto de resultados se almacene en libmysql (fuera de los límites de memoria de PHP) y luego PHP solo asignará la memoria real requerida para mantener el registro al obtenerlo:

    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result( $status );
    $stmt->fetch();
    
  • Aumentar el límite de memoria de PHP para que pueda acomodar la asignación de búferes de 4GiB (aunque uno debe ser consciente de las implicaciones en los recursos de hardware al hacerlo), por ejemplo, para eliminar las restricciones de memoria por completo (aunque tenga en cuenta los posibles efectos secundarios negativos de hacer esto, por ejemplo, de pérdidas de memoria genuinas):

    ini_set('memory_limit', '-1');
    
  • Recompilando PHP, configurado para usar el controlador mysqlnd nativo (incluido con PHP desde v5.3.0, pero no configurado como predeterminado hasta PHP v5.4.0) en lugar de libmysql:

    ./configure --with-mysqli=mysqlnd
    
  • Actualizar a PHP v5.4.0 o posterior para que mysqlnd se use de manera predeterminada.