Mysql
 sql >> Datenbank >  >> RDS >> Mysql

PHP mysql_stmt::fetch() gibt PHP Fatal error memory erschöpft

Sie werden feststellen, dass dies nur geschieht wenn @status ist NULL oder eine Zeichenfolge.

Das Problem ist zweierlei:

  1. Im Gegensatz zu lokalen Variablen , MySQL Benutzervariablen unterstützen eine sehr begrenzte Menge von Datentypen:

    Die Dokumentation erwähnt nicht, dass die tatsächlichen Datentypen verwendet werden jeweils BIGINT , DECIMAL(65,30) , DOUBLE , LONGBLOB , LONGTEXT und LONGBLOB . Zu letzterem erklärt das Handbuch zumindest:

    Speicherung der ersten drei dieser Datentypen (d. h. für Integer-, Dezimal- und Fließkommawerte) benötigen jeweils 8, 30 und 8 Bytes. Die anderen Datentypen (also für String und NULL -Werte) erfordern (bis zu) 4 Gigabyte Speicherplatz.

  2. Da Sie eine PHP-Version vor v5.4.0 verwenden, ist der standardmäßige MySQL-Treiber libmysql , mit dem nur Spaltentyp-Metadaten vom Server bei der Datenbindung verfügbar sind – also versucht MySQLi, ausreichend Speicher zuzuweisen, um jeden möglichen Wert zu halten (auch wenn der volle Puffer letztendlich nicht benötigt wird); also NULL - und Benutzervariablen mit Zeichenfolgenwerten, die eine maximal mögliche Größe von 4 GiB haben, bewirken, dass PHP sein Standardspeicherlimit (von 128 MiB seit PHP v5.2.0) überschreitet.

Ihre Optionen umfassen:

  • Überschreiben des Spaltendatentyps in der Tabellendefinition:

    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table (
      status VARCHAR(2)
    ) SELECT @status AS status;
    
  • Explizit casting die Benutzervariable in einen spezifischeren Datentyp:

    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT CAST(@status AS CHAR(2)) AS status;
    
  • Verwendung lokaler Variablen, die mit einem expliziten Datentyp deklariert sind:

    DECLARE status VARCHAR(2) DEFAULT @status;
    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT status;
    
  • Problemumgehung durch Aufrufen von mysqli_stmt::store_result() vorher mysqli_stmt::bind_result() , was dazu führt, dass die Ergebnismenge in libmysql gespeichert wird (außerhalb der Speichergrenzen von PHP) und PHP dann nur den tatsächlichen Speicher zuweist, der erforderlich ist, um den Datensatz beim Abrufen zu halten:

    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result( $status );
    $stmt->fetch();
    
  • Erhöhung des Speicherlimits von PHP damit es die Zuweisung von 4GiB-Puffer aufnehmen kann (obwohl man sich der Auswirkungen auf die Hardware-Ressourcen bewusst sein sollte) – zum Beispiel, um die Speicherbeschränkungen vollständig zu entfernen (obwohl man sich der potenziellen negativen Nebenwirkungen bewusst sein kann, dies zu tun, z.B. von echten Speicherlecks):

    ini_set('memory_limit', '-1');
    
  • Neukompilieren von PHP, konfiguriert zur Verwendung von dem nativen mysqlnd-Treiber (in PHP seit v5.3.0 enthalten, aber bis PHP v5.4.0 nicht als Standard konfiguriert) anstelle von libmysql:

    ./configure --with-mysqli=mysqlnd
    
  • Upgrade auf PHP v5.4.0 oder höher, sodass mysqlnd standardmäßig verwendet wird.