Если вы посмотрите по Интернету (например, Каков максимальный размер запроса для mysql? ), вы обнаружите утверждения, что максимальный размер запроса для MariaDB / MySQL равен значению переменной max_allowed_packet
, Но когда вы действительно попробуете это, вы обнаружите, что это не совсем так.
Вот небольшой скрипт Lua, который генерирует тестовый запрос нужного размера:
prefix = "SELECT IF(0,'"
postfix = "',NULL);"
max_allowed_packet = 16777216 -- The value for my setup
function gen_query(size)
local n = size - string.len(prefix) - string.len(postfix)
local query = prefix .. string.rep('X', n) .. postfix
io.open("/tmp/testquery.sql", "w"):write(query):close()
end
gen_query(max_allowed_packet)
/tmp/testquery.sql
теперь содержит запрос типа SELECT IF(0,'<a lot of Xs here>',NULL);
.
Если мы сейчас попробуем выполнить это, мы получим ошибку:
$ mysql -A -B < /tmp/testquery.sql
ERROR 1153 (08S01) at line 1: Got a packet bigger than 'max_allowed_packet' bytes
Если мы сделаем то же самое, но с gen_query(max_allowed_packet - 1)
(генерируя запрос на один байт меньше), сервер успешно выполнит запрос:
$ mysql -uroot -pmysql --protocol=tcp -A -B < /tmp/testquery.sql
IF(0,'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
NULL
Если мы копаемся с документацией MySQL (не может найти эквивалент для MariaDB), это начинает иметь смысл, так как пакет включает дополнительный байт (0x03), который объявляет пакет как COM_QUERY
пакет: https://dev.mysql.com/doc/internals/en/com-query.html
Пока это все имеет смысл для меня, но если мы пойдем дальше и изменим нашу программу lua, чтобы она не включала точку с запятой в конце (установив postfix = "',NULL)"
), это неожиданно снова результат:
$ mysql -uroot -pmysql --protocol=tcp -A -B < /tmp/testquery.sql
ERROR 1153 (08S01) at line 1: Got a packet bigger than 'max_allowed_packet' bytes
Тестовый запрос по-прежнему max_allowed_packet - длиной 1 байт:
$ wc -c /tmp/testquery.sql
16777215 /tmp/testquery.sql
max_allowed_packet - запрос длиной 2 байта без точки с запятой снова работает, как и ожидалось.
Что происходит? Вставляет ли клиент командной строки mysql
/ библиотека mysql автоматически ;
в конце? Насколько я могу сказать, это не так, вот выдержка из вывода strace:
$ strace -v -e write=3 mysql -A -B < /tmp/testquery.sql
<<< irrelevant syscalls omitted >>>
sendto(3, "\377\377\377\0\3SELECT IF(0,'XXXXXXXXXXXXXX"..., 16384, 0, NULL, 0) = 16384
| 00000 ff ff ff 00 03 53 45 4c 45 43 54 20 49 46 28 30 .....SELECT IF(0 |
| 00010 2c 27 58 58 58 58 58 58 58 58 58 58 58 58 58 58 ,'XXXXXXXXXXXXXX |
<<< lots of hexdump data omitted >>>
| ffbff0 58 58 58 58 58 58 58 58 58 58 58 58 27 2c 20 4e XXXXXXXXXXXX', N |
| ffc000 55 4c 4c ULL |
sendto(3, "\1\0\0\1)", 5, 0, NULL, 0) = 5
| 00000 01 00 00 01 29 ....) |
<<< more irrelevant syscalls omitted >>>
Могу ли я отправить запрос max_allowed_packet - длиной 2 байта и всегда ожидать, что он будет работать (если, конечно, в запросе sql нет ошибок :))? И задокументировано ли это поведение где-нибудь?