如果您环顾互联网(例如What is maximum query size for 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查询中没有错误,当然:))?并在某处记录了此行为吗?