如果我读到这个问题,我会立即想到"一些白痴在自己做研究之前寻求帮助"。虽然" idiot"是否仍有待观察指定是正确的,我可以向你保证,这不是我的第一次牛仔竞技表演,而且我已经在这面墙上击打了40-80小时。
短篇小说:我的系统执行4次更新语句四次传入四个不同的参数值。根据约束,每次执行应修改大约50,000行。但是,虽然其中两个执行修改了预期的行数,但另外两个只更新了201行。
声明: 为了说服你,我不是一个菜鸟,谁正在更新一个数据库,然后想知道为什么不同数据库中的记录没有更新。
长篇故事:
有问题的表格如下:
有一个非聚集索引,只包含MyForeignKeyCol1
(不包含)。
还有另一个非聚集索引,只包含MyForeignKeyCol2
(不包括)。
MyForeignKeyCol1
有一个外键,MyForeignKeyCol2
有另一个外键。
更新声明是:
UPDATE T1
SET MyForeignKeyCol1 = NULL,
MyForeignKeyCol2 = NULL,
MyIntCol = NULL
WHERE MyForeignKeyCol2 = ?
问题非常不一致。我已经将该过程运行了200-300次,问题仅发生了3次。
在最近发生的事件中,该表包含大约200,000条记录。 50,000 MyForeignKeyCol2
中包含值123,MyForeignKeyCol2
中50,000包含值345,MyForeignKeyCol2
中50,000包含值567,{{1}中包含值789 }}
该过程执行Update语句4次,传递参数123,345,567和789. 4个更新中的每一个都在单独的事务中执行。数据库驱动程序报告语句修改了以下数量的记录:
数据库的状态显示49,799条记录保留MyForeignKeyCol2
,另有49,799条记录保留MyForeignKeyCol2=345
。
数据库不包含触发器。
我的第一个理论之一是,在执行UPDATE时,跳过的记录上的MyForeignKeyCol2=567
列包含除345或567之外的某些值,然后在UPDATE后面的某些内容用这些值填充列。经过数小时的研究后,99.99%肯定不是这样。
此类行为是否可能是由腐败索引或过时统计信息引起的?
根据我的经验,数据库是我参与的任何系统中最可靠的部分,因此也是我怀疑的最后一件事,但这是我唯一留下的理论。
提前致谢!
答案 0 :(得分:2)
我仍然没有完整的答案,但我现在已经足够明白,可以将其标记为已回答,以避免其他人浪费时间。有了它,我会提供完整的答案。
注意:我没有提到这是一个Java应用程序。
它似乎是另一个线程(一个服务于某些UI活动的线程),它获取了这个java.sql.Statement对象的句柄,并在第一个和第二个UPDATES之间调用了Statement.setMaxRows(201)。然后可能会再次称它为第三次和第四次更新之间的大量传递。
我总觉得setMaxRows只影响SELECT语句,而该方法的javadoc支持这种误解(IMO)。但是我现在明白它也会影响UPDATE,DELETES和INSERTS(不是100%肯定INSERTS)。将此字段设置为201会导致JTDS驱动程序发送" SET ROWCOUNT 201"在UPDATE语句之前命令SQL Server,这导致SQL Server将UPDATE影响的行数限制为201.
现在剩下的问题是"另一个线程如何处理该连接"?我们使用连接池库,我们还有另一个库,可以帮助进行数据库事务管理。我现在避免命名它们,b / c最可能的罪魁祸首是我们的代码(一如既往)。
感谢所有花费宝贵时间阅读这个长期问题的人。
最终答案!!! 这是JTDS驱动程序的最新版本(1.3.1)中的错误。 https://sourceforge.net/p/jtds/bugs/726/
再次感谢任何花时间审阅我的问题的人!