U zult zien dat dit alleen gebeurt wanneer @status
is NULL
of een string.
Het probleem is tweeledig:
-
In tegenstelling tot lokale variabelen , MySQL gebruikersvariabelen ondersteunen een zeer beperkte set datatypes:
De documentatie vermeldt niet dat de werkelijke datatypes gebruikt zijn respectievelijk
BIGINT
,DECIMAL(65,30)
,DOUBLE
,LONGBLOB
,LONGTEXT
enLONGBLOB
. Wat de laatste betreft, legt de handleiding in ieder geval uit:Opslag van de eerste drie van deze datatypes (d.w.z. voor integer, decimal en floating-point waarden) vereisen respectievelijk 8, 30 en 8 bytes. De andere datatypes (d.w.z. voor string en
NULL
waarden) vereisen (tot) 4 gigabyte opslagruimte. -
Aangezien u een versie van PHP gebruikt die ouder is dan v5.4.0, is het standaard MySQL-stuurprogramma libmysql , waarbij alleen metagegevens van het kolomtype beschikbaar zijn van de server bij gegevensbinding - dus MySQLi probeert voldoende geheugen toe te wijzen om elke mogelijke waarde vast te houden (zelfs als de volledige buffer uiteindelijk niet nodig is); dus
NULL
- en gebruikersvariabelen met stringwaarde, die een maximaal mogelijke grootte van 4GiB hebben, zorgen ervoor dat PHP zijn standaard geheugenlimiet overschrijdt (van 128 MiB sinds PHP v5.2.0).
Uw opties omvatten:
-
Het kolomgegevenstype in de tabeldefinitie overschrijven:
DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table ( status VARCHAR(2) ) SELECT @status AS status;
-
Expliciet casten de gebruikersvariabele naar een specifieker datatype:
DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT CAST(@status AS CHAR(2)) AS status;
-
Lokale variabelen gebruiken, die zijn gedeclareerd met een expliciet datatype:
DECLARE status VARCHAR(2) DEFAULT @status; DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT status;
-
Het probleem omzeilen door
mysqli_stmt::store_result()
aan te roepen voormysqli_stmt::bind_result()
, waardoor de resultatenset wordt opgeslagen in libmysql (buiten de geheugenlimieten van PHP) en dan zal PHP alleen het daadwerkelijke geheugen toewijzen dat nodig is om het record vast te houden bij het ophalen:$stmt->execute(); $stmt->store_result(); $stmt->bind_result( $status ); $stmt->fetch();
-
PHP's geheugenlimiet verhogen zodat het de toewijzing van 4GiB-buffers kan accommoderen (hoewel men zich bewust moet zijn van de implicaties voor hardwarebronnen hiervan) - bijvoorbeeld om de geheugenbeperkingen volledig te verwijderen (hoewel u zich bewust moet zijn van mogelijke negatieve bijwerkingen hiervan, bijvoorbeeld van echte geheugenlekken):
ini_set('memory_limit', '-1');
-
PHP hercompileren, geconfigureerd om de native mysqlnd-driver te gebruiken (meegeleverd met PHP sinds v5.3.0, maar niet als standaard geconfigureerd tot PHP v5.4.0) in plaats van libmysql:
./configure --with-mysqli=mysqlnd
-
Upgraden naar PHP v5.4.0 of hoger zodat mysqlnd standaard wordt gebruikt.