当查询以分号结尾时,最大查询大小为何会有所不同?

时间:2018-08-28 14:21:58

标签: mysql sql mariadb

如果您环顾互联网(例如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_pa​​cket-1个字节长:

$ wc -c /tmp/testquery.sql
16777215 /tmp/testquery.sql

一个max_allowed_pa​​cket-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_pa​​cket-2字节长的查询,并且总是希望它能工作(如果sql查询中没有错误,当然:))?并在某处记录了此行为吗?

0 个答案:

没有答案