首页 > 数据库 > 数据库开发技术 > 一个关于mysql_info()的冷知识
总所周知,由于InnoDB没有存储表的总行数,每次执行select count(*)的时候都要做全表扫描。对于一些数据量比较大的表,这个操作的成本还挺高。
因此有些业务会用一个辅助表记录某个表的总行数,在业务有增删改的时候,手动把总行数更新到辅助表里。
这样在需要表的总行数时候,就直接从辅助表读。
但是对于表上有insert ... on duplicate (IOD)语句的业务来说,怎么获取一个语句执行后,表行数的变化量,就需要额外的处理逻辑。
这篇就介绍一下怎么从IOD的返回信息中获取表行数的变化。
分成两类情况:IOD里 insert后面只有一行数据 和 有多行数据。
建一个示例表,表里只有id一个主键,并插入两行。
create table t1(id int primary key , a int, b int);
insert into t1 values(1,1,1),(2,2,2);
1. insert一行数据:
分三种执行结果
a) insert into t1 values(3,3,3) on duplicate key update b=b+1;
这是没有唯一键冲突的情况,affected_rows = 1
b) insert into t1 values(1,1,1) on duplicate key update b=b+1;
这是有唯一键冲突并且更新了数据行的情况,affected_rows = 2
c) insert into t1 values(1,1,1) on duplicate key update b=b+0;
这是有唯一键冲突并且没有更新行的情况,affected_rows = 0
其中b)这种情况,看着像bug,不过官方文档上也特别做了说明,就不要认为bug了,当做是feature吧。
2. insert多行数据
insert into t1 values(1,1,1),(2,2,2),(4,4,4) on duplicate key update b=b*10;
我们看一下执行效果。

可以看到结果是id=1和id=2这两行的d值修改了, 又插入了id=4的一行。
顺着上面b)的结果,这个affected_rows=5好像也能理解了:就是update成功一行算2行,但是这个affected_rows已经完全无法指导我们判断总行数的变化了。
好在下面还有一行 Records: 3 Duplicates: 2 Warnings: 0,说得还挺清晰,要插入3行,重复了2行,因此总行数加1。
那这个信息从客户端怎么获取呢?用mysql_info()这个api,会返回整行字符串,然后客户端自己解析吧。
这个方法之前也没看到哪个文章说过,刷代码刷出来的,然后到官方看了这个api的说明,人家早就水灵灵的写着呢。

从这个说明联想一下,insert ignore 也可以这么判断,做了下试验,果然。。

好吧,又是被文档补缺补漏的一天。
总结一下,
当IOD语句里,insert后面跟一行数据的情况,用affected_rows判断,是1则总行数加1,否则总行数不变。
insert后面跟多行数据的情况, 用mysql_info里的数字计算,Records减去Duplicates就是增加的行数。
==E
这个问题是昨天跟一个群友讨论一个生产上的问题时提到的。
还没有加入 MySQL45.x 讨论群的同学,欢迎来聊。

OF==
原文作者:丁奇3306;如有侵权,请联系管理员删除。