Mysql
 sql >> Base de données >  >> RDS >> Mysql

PHP mysql_stmt ::fetch() donne une mémoire d'erreur fatale PHP épuisée

Vous constaterez que cela se produit uniquement quand @status est NULL ou une chaîne.

Le problème est double :

  1. Contrairement aux variables locales , MySQL variables utilisateur prend en charge un ensemble très limité de types de données :

    La documentation ne mentionne pas que les types de données réels utilisés sont respectivement BIGINT , DECIMAL(65,30) , DOUBLE , LONGBLOB , LONGTEXT et LONGBLOB . Concernant le dernier, le manuel explique au moins :

    Stockage des trois premiers de ces types de données (c'est-à-dire pour les valeurs entières, décimales et à virgule flottante) nécessitent respectivement 8, 30 et 8 octets. Les autres types de données (c'est-à-dire pour string et NULL valeurs) nécessitent (jusqu'à) 4 gigaoctets de stockage.

  2. Puisque vous utilisez une version de PHP antérieure à la v5.4.0, le pilote MySQL par défaut est libmysql , avec lequel seules les métadonnées de type colonne sont disponibles à partir du serveur lors de la liaison des données. MySQLi tente donc d'allouer suffisamment de mémoire pour contenir toutes les valeurs possibles (même si le tampon complet n'est finalement pas requis) ; donc NULL - et les variables utilisateur de type chaîne, qui ont une taille maximale possible de 4 Gio, obligent PHP à dépasser sa limite de mémoire par défaut (de 128 Mo depuis PHP v5.2.0).

Vos options incluent :

  • Remplacer le type de données de colonne dans la définition de table :

    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table (
      status VARCHAR(2)
    ) SELECT @status AS status;
    
  • Explicitement diffusion la variable utilisateur à un type de données plus spécifique :

    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT CAST(@status AS CHAR(2)) AS status;
    
  • Utilisation de variables locales, qui sont déclarées avec un type de données explicite :

    DECLARE status VARCHAR(2) DEFAULT @status;
    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT status;
    
  • Contourner le problème en appelant mysqli_stmt::store_result() avant mysqli_stmt::bind_result() , ce qui entraîne le stockage du jeu de résultats dans libmysql (en dehors des limites de mémoire de PHP), puis PHP n'allouera que la mémoire réelle requise pour conserver l'enregistrement lors de sa récupération :

    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result( $status );
    $stmt->fetch();
    
  • Augmentation de la limite de mémoire de PHP afin qu'il puisse accueillir l'allocation de tampons de 4 Go (bien qu'il faille être conscient des implications sur les ressources matérielles de le faire) - par exemple, pour supprimer entièrement les contraintes de mémoire (bien que soyez conscient des effets secondaires négatifs potentiels de cette opération, par exemple à partir de véritables fuites de mémoire):

    ini_set('memory_limit', '-1');
    
  • Recompilation de PHP, configuré pour utiliser le pilote mysqlnd natif (inclus avec PHP depuis la v5.3.0, mais non configuré par défaut jusqu'à PHP v5.4.0) au lieu de libmysql :

    ./configure --with-mysqli=mysqlnd
    
  • Mise à niveau vers PHP v5.4.0 ou version ultérieure afin que mysqlnd soit utilisé par défaut.