一例数据同步异常问题分析
【问题描述】
开发反馈,有一个sql server数据同步的作业,从table1 拉取数据,主键是id, 每次拉取批次数据的sql语句是 select top (15) * from table1(nolock) where id > ?,?代表的是上次同步批次中最后一个id号。
某一次拉取到的数据为 id: 8101102121,8101103081 两条数据。查表发现,这两条记录中间,还有一条记录,即id=8101102855,这条记录没有被拉取到。十分困惑,为什么会少拉一条记录,是否拉取的时候,该条记录没有被创建?
createtime | id | column3 | column4 |
---|---|---|---|
2019-04-11 14:17:14.843 | 8101102121 | 已处理 | |
2019-04-11 14:17:17.190 | 8101102855 | 已处理 | |
2019-04-11 14:17:20.237 | 8101103081 | 已处理 |
【问题分析】
刚开始看这个问题,也觉得非常奇怪。这个查询语句中规中矩,从应用日志来看,两个id之间的8101102855 确实是没有被拉取到。
为进一步定位问题,我们分析具体的查询语句。由于我们的服务器开启了xevent trace,我们定位到,当时在数据库服务器端真正执行的语句如下,比开发反馈的更多一些条件:
select top 15 id from table1 with (nolock) where id > 8101101700 and column4 not like '%(特殊需求)%' and createtime > '2018-07-19 00:00:00.000' order by id asc
我们用这个查询,在当前时间(2019-04-12 17:23:00)数据库上进行查询,确实能返回三条记录。
通过数据库明细记录, 该语句在数据库上的执行时间是:2019-04-11 14:17:21。对于id=8101102855的记录,其插入的时间是2019-04-11 14:17:17.190,比我们的查询时间早4秒,按道理应该是能查出来的。另外,在2019-04-11 14:17:21的时候,id=8101102855 的记录正在被更新。难道是我们的查询带了nolock,所以当前正在被更新的记录跳过了?
根据我们的理解,nolock相当于read uncommitted, 是会读取其他事务“修改后未提交的“数据。也就是说,是能够读出主键id的。
【问题重现】
为了能够更好的分析问题,我们定点还原数据库,还原到2019-04-11 14:17:20的时候,也就是比应用的查询时间早1秒钟。其数据记录如下。在这个点上,id=8101103081 还没有插入进来,但id=8101102855,也就是我们关注的id,数据已经进来了。
createtime | id | column3 | column4 |
---|---|---|---|
2019-04-11 14:17:14.843 | 8101102121 | 已处理 | |
2019-04-11 14:17:17.190 | 8101102855 |
针对上面的数据,我们执行查询:
select top 15 id from table1 with (nolock) where id > 8101101700 and column4 not like '%(特殊需求)%' and createtime > '2018-07-19 00:00:00.000' order by id asc
奇怪的发现,这个查询只返回id=8101102121,id=8101102855没有返回。经过简单的调试,我们很快发现,是由于这个查询条件所致:
column4 not like '%(特殊需求)%'
id=8101102855记录在刚插入的时候,其column4的值为null,从语义上来讲,确实是不包含"(特殊需求)"这个字符串的。但在sql处理上,却和我们理解的不一样。
sql除了is null和not null以外,只要出现null,值结果为false。简单来说,对于查询select * from table where name != ‘test’,只要name值是null,无论用name=’test’还是name != 'test', 都不能返回这一行。如果要返回的话,需要加is null判断:
select * from table where name != ‘test’ or name is null
至此,问题真相大白,解决方案也就很简单:调整查询语句,加一个is null判断即可。
select top 15 id from table1 with (nolock) where id > 8101101700 and (column4 not like '%(特殊需求)%' or column4 is null) and createtime > '2018-07-19 00:00:00.000' order by id asc
【结论】
数据库在碰到null的处理时候,要小心,查询的判断条件并不是很明显,要注意is null的情况。
上一篇: 你知道松花蛋的制作材料有哪些吗?
下一篇: SqlServer无备份下误删数据恢复
推荐阅读
-
JAVAEE——宜立方商城06:Redis安装、数据类型和持久化方案、Redis集群分析与搭建、实现缓存和同步
-
Python基于多线程操作数据库相关问题分析
-
mybatis oracle proc 数据库测试没问题,java调用就异常 ORA-00900: 无效 SQL 语句
-
深入SqlServer2008 数据库同步的两种方式(Sql JOB)的分析介绍
-
百度竞价数据分析 你的问题,我来解答
-
SQLServer乱码问题的分析及解决方法(中文字符被存入数据库后,显示为乱码)
-
云端数据库安全问题分析
-
oracle数据库之相关数据字典进行性能问题分析
-
Oracle在线及重做日志分析数据同步实例
-
对于使用JDBC连接mysql数据时The server time zone value '¤¤°ê¼Ð·Ç®É¶¡'...的异常问题解决。