sql >> Databáze >  >> RDS >> Mysql

PHP mysql_stmt::fetch() způsobí vyčerpání paměti pro závažnou chybu PHP

Zjistíte, že k tomu dochází pouze když @status je NULL nebo řetězec.

Problém je dvojí:

  1. Na rozdíl od místních proměnných , MySQL uživatelské proměnné podporují velmi omezenou sadu datových typů:

    Dokumentace nezmiňuje, že skutečné datové typy použité jsou v tomto pořadí BIGINT , DECIMAL(65,30) , DOUBLE , LONGBLOB , LONGTEXT a LONGBLOB . Pokud jde o poslední, manuál alespoň vysvětluje:

    Úložiště z prvních tří těchto datových typů (tj. pro celočíselné, desetinné a plovoucí desetinné čárky) vyžadují 8, 30 a 8 bajtů. Ostatní datové typy (tj. pro řetězec a NULL hodnoty) vyžadují (až) 4 gigabajty úložiště.

  2. Protože používáte verzi PHP starší než v5.4.0, výchozí ovladač MySQL je libmysql , se kterým jsou ze serveru po navázání dat k dispozici pouze metadata typu sloupce – takže se MySQLi pokouší alokovat dostatek paměti pro uchování všech možných hodnot (i když není nakonec potřeba plná vyrovnávací paměť); tedy NULL - a uživatelské proměnné s hodnotou řetězce, které mají maximální možnou velikost 4GiB, způsobí, že PHP překročí svůj výchozí limit paměti (128MiB od PHP v5.2.0).

Vaše možnosti zahrnují:

  • Přepsání datového typu sloupce v definici tabulky:

    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table (
      status VARCHAR(2)
    ) SELECT @status AS status;
    
  • Explicitně casting uživatelskou proměnnou na specifičtější datový typ:

    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT CAST(@status AS CHAR(2)) AS status;
    
  • Pomocí lokálních proměnných, které jsou deklarovány s explicitním datovým typem:

    DECLARE status VARCHAR(2) DEFAULT @status;
    DROP TEMPORARY TABLE IF EXISTS tmp_table;
    CREATE TEMPORARY TABLE tmp_table
      SELECT status;
    
  • Problém vyřešíte voláním mysqli_stmt::store_result() před mysqli_stmt::bind_result() , což způsobí, že výsledná sada bude uložena v libmysql (mimo paměťové limity PHP) a PHP poté po načtení alokuje pouze skutečnou paměť potřebnou k udržení záznamu:

    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result( $status );
    $stmt->fetch();
    
  • Zvyšování limitu paměti PHP PHP tak, aby se mohl přizpůsobit alokaci 4GiB vyrovnávacích pamětí (ačkoli by si člověk měl být vědom důsledků na hardwarové zdroje z toho plynoucí) – například za účelem úplného odstranění omezení paměti (ačkoli je třeba si být vědom potenciálních negativních vedlejších účinků tohoto postupu, např. z originálních úniků paměti):

    ini_set('memory_limit', '-1');
    
  • Překompilování PHP, nakonfigurované pro použití nativního ovladače mysqlnd (součástí PHP od verze 5.3.0, ale není nakonfigurováno jako výchozí až do verze PHP v5.4.0) namísto libmysql:

    ./configure --with-mysqli=mysqlnd
    
  • Upgrade na PHP v5.4.0 nebo novější, aby se ve výchozím nastavení používal mysqlnd.




  1. Chování plánu dotazů dočasné tabulky SQL Server 2016

  2. 911/112:Datový model služby tísňového volání

  3. Jak vytisknout tabulku databáze MySQL v PHP pomocí PDO

  4. Přesunutí tabulky serveru SQL do jiné skupiny souborů