mysql INSERT не работает, но ошибки не возникает: max_allowed_packet: настройки показывают противоречивые результаты

Я успешно получаю данные в учетную запись клиента сервера через _POST, но я не могу вставить данные в таблицу строк, содержащую типы longblob, когда данные строки превышают ~25 МБ. Я не вижу никаких ошибок, вызванных подготовленными операторами / файлом php, файл php закрывается изящно. Я проверяю, правильно ли настроен мой max_allowed_packet.

У меня нет корневых привилегий и доступа к серверу, я не вижу my.cnf, и я разговариваю со своим хостом, чтобы убедиться, что max_allowed_packet клиента и сервера установлены на 256M.

Раздел вставки файла php:

$itemAttributes=$_POST['itemAttributes'];
$itemName=$_POST['itemName'];

if(!($stmt = $conn->prepare("INSERT INTO $itemTable (`itemName`, `itemAttributes`) VALUES (?, ?)")))
        echo "<br/>Failed to Prepare";
        else
          echo "<br/>Prepare success.";  

$stmt->execute([$itemName,$itemAttributes]);
          echo " Success executing";

$conn->connection=null;
if($conn->connection==null)
  echo "<br />Connection Closed.......";

Это проверки, которые я выполняю, не хватает ли мне каких-либо, чтобы убедиться, что max_allowed_packet не будет переопределен в другом месте и правильно настроен во всех местах?

Проверка настроек клиента: все эти три проверки дают мне max_allowed_packet 256 МБ:

mysql SHOW VARIABLES LIKE 'max_allowed_packet' 
mysql SHOW GLOBAL VARIABLES LIKE 'max_allowed_packet'
mysql SHOW SESSION VARIABLES LIKE 'max_allowed_packet'

Однако я успешно вхожу в командную строку mysql (mysql --user userName --password databaseName), чтобы проверить max_allowed_packet, но он показывает NULL, что это значит?

mysql> select @max_allowed_packet;
+---------------------+
| @max_allowed_packet |
+---------------------+
| NULL                |
+---------------------+
1 row in set (0.00 sec)

Проверка настроек сервера: как я могу проверить сервер max_allowed_packet на предмет GLOBAL и SESSION? Я пытаюсь заменить "mysql" на "mysqld", но не получаю никаких результатов и предупреждений, которые я не могу связать с размером max_allowed_packet:

[useraccount@cloud ~]$ mysqld SHOW GLOBAL VARIABLES LIKE 'max_allowed_packet'
2020-02-12T07:47:33.832292Z 0 [Warning] Could not increase number of max_open_files to more than 1024 (request: 65536)
2020-02-12T07:47:33.832480Z 0 [Warning] Changed limits: max_connections: 214 (requested 256)
2020-02-12T07:47:33.832487Z 0 [Warning] Changed limits: table_open_cache: 400 (requested 2000)
2020-02-12T07:47:33.945335Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2020-02-12T07:47:33.945476Z 0 [Warning] Can't create test file /var/lib/mysql/cloud.lower-test
2020-02-12T07:47:33.945569Z 0 [Note] mysqld (mysqld 5.7.29) starting as process 75 ...
2020-02-12T07:47:33.947615Z 0 [Warning] Can't create test file /var/lib/mysql/cloud.lower-test
2020-02-12T07:47:33.947631Z 0 [Warning] Can't create test file /var/lib/mysql/cloud.lower-test
2020-02-12T07:47:33.948025Z 0 [ERROR] Could not open file '/var/log/mysqld.log' for error logging: Permission denied
2020-02-12T07:47:33.948066Z 0 [ERROR] Aborting
2020-02-12T07:47:33.948138Z 0 [Note] Binlog end
2020-02-12T07:47:33.948287Z 0 [Note] mysqld: Shutdown complete

Проверка mysqldump: наконец, я пытаюсь прочитать max_allowed_packet для mysqldump с помощью трех вышеперечисленных команд (т.е. mysqldump SHOW VARIABLES LIKE 'max_allowed_packet'), заменяя mysql на mysqldump, но мне отказано в доступе. В качестве альтернативы я затем успешно вхожу в mysqldump, чтобы прочитать max_allowed_packet (mysqldump --user userName --password databaseName), и я получаю много мусора, прокручивающего экран, поэтому я не могу получить это значение.

1 ответ

Как оказалось, это не имеет ничего общего с MySQL напрямую.

Неустранимая ошибка: разрешенный объем памяти 134217728 байт исчерпан (попытка выделить 32000179 байт) в /home/client/public_html/phpfile.php в строке 175

Это сообщение об ошибке PHP, которое сообщает вам, что ваш скрипт превысил ограничение памяти 128 МБ.

Вы можете увеличить лимит либо в файле конфигурации, либо в сценарии с помощью

ini_set('memory_limit','256M');

Ты можешь использовать -1 как значение, чтобы полностью отключить ограничение.

Однако вам следует избегать копирования больших объемов данных.

Ясно следующий случай:

$itemAttributes=$_POST['itemAttributes'];

Вы копируете 32M данных в новую переменную. И ваш скрипт сейчас как минимум 64M.

В execute() метод с параметрами более сложен, и я не уверен, верно ли следующее: вы передаете новый массив в качестве параметра

[$itemName,$itemAttributes]

Этот массив сначала необходимо создать в памяти, прежде чем он будет передан в execute(). Это опять же потребляет как минимум на 32 млн больше. Затем из-за внутренней реализации (которой я не знаю) каждый элемент массива передается во что-то вродеbindValue(), который снова скопирует все данные. На данный момент ваш скрипт уже имеет ограничение 128M (32*4).

Итак, вы должны сделать что-то вроде следующего:

Удалите эти строки:

$itemAttributes=$_POST['itemAttributes'];
$itemName=$_POST['itemName'];

Подготовьте выписку:

$stmt = $conn->prepare("INSERT INTO $itemTable (`itemName`, `itemAttributes`) VALUES (?, ?)");

Свяжите параметры с помощью bindParam:

$stmt->bindParam(1, $_POST['itemName'], PDO::PARAM_STR);
$stmt->bindParam(2, $_POST['itemAttributes'], PDO::PARAM_LOB);

bindParam()использует вызов по ссылке, которую вы можете увидеть в описании

public PDOStatement::bindParam (смешанный параметр $, смешанный &$ переменная [, int $data_type = PDO::PARAM_STR [, int $length [, смешанный $driver_options ]]]): bool

& в &$variableуказывает, что копирование не будет выполнено, но вместо этого будет передана ссылка на значение.

Обратите внимание, что я обычно не сторонник обращения по ссылке и избегаю этого, когда не имею дела с критически важным кодом.execute([..]) в большинстве случаев нормально.

Если вы хотите увидеть, сколько памяти было выделено, вы можете использовать memory_get_peak_usage() где-нибудь в конце вашего скрипта.

Другие вопросы по тегам