首页 新闻 会员 周边

一个耗时Insert的问题

0
悬赏园豆:40 [已解决问题] 解决于 2015-05-30 12:51

向一张表中插入数据,加了Transaction。在Insert之前先用查询判断数据是否已经在数据库中存在(业务主键)。若数据量大比较耗时,前一次Transaction还未完成就再次插入同样的数据,就会导致业务主键重复。这问题该怎么解决?
1. 业务主键加唯一约束。但逻辑删除的数据可能会违反约束。
2. 加表锁。整张表都锁住,也不太好啊。

求助!!!

问题补充:

貌似可以用lock

心亦的主页 心亦 | 初学一级 | 园豆:163
提问于:2015-05-14 20:10
< >
分享
最佳答案
0

你难道没办法先检查所有插入的数据,把重复的排除?

收获园豆:40
爱编程的大叔 | 高人七级 |园豆:30839 | 2015-05-14 20:48

是这样的,插入之前做过重复判断。第一次插入,Transaction还没完成。所以第二次插入前数据库中还没,这样就导致重复了。

心亦 | 园豆:163 (初学一级) | 2015-05-14 21:50

@心亦: 还原一下你的场景,

1、多线程。

2、只要是多线程,不管是大数据,还是小数据,理论上都存在第一次插入没完成的情况下,

第二次检测已经发生。就是说不管你执行速度有多快,0.1NS也好,都存在并发考虑。

3、那么为啥会出现一线程和二线程有相同的业务数据,能不能在这个上面思考一下呢?

 

你是想解决问题呢,还是只想从一个方向解决问题?

爱编程的大叔 | 园豆:30839 (高人七级) | 2015-05-15 09:55

@爱编程的大叔: 这个业务数据是用户提供,也没法控制。

最后的问句没读懂啊。想解决问题的

心亦 | 园豆:163 (初学一级) | 2015-05-15 10:03

@心亦: 那么再问一句,瓶颈是数据库,还是CPU计算能力?

1、如果是数据库的话,可以考虑不要多线程。

2、业务数据用户提供?包括主键?(比如像我们使用的主键是无任何意义的GUID,与业务无关)

3、延时5分钟,排队(类似MSMQ),只用一个线程(或者多线程也行),这样5分钟内的数据可以先

保证这部分数据是不重复的。(不会出现一线程没完成的业务,和二线程的检测无效的问题)

4、即便你的信息比较不方便透露,但是你可以将一些关键点说下的,

比如数据怎么来:每分钟过来500条数据,每天24小时不间断。

数据怎么组织? 比如说数据是 客户、日期、金额,单据号。单据号可能重复,重复的话使用第一条还是第二条,因为什么原因重复了,能不能在前一道工序上去重?

为啥主键是没法自行控制的?

为啥会出现同样的业务数据?

能不能插入前(我指不通过数据库检测直接去重复)排除?

数据处理的时效性要求?

爱编程的大叔 | 园豆:30839 (高人七级) | 2015-05-15 10:11

@爱编程的大叔: 

1 数据库单线程的方法请指教一下。

2 是用户提供主键

3 引入队列好像会更加复杂

4 数据是wcf post来的,用户频繁操作两次导致了这个问题。要在代码去重,那肯定要将一定时间内的数据缓存起来,和3的方案相同吧。

心亦 | 园豆:163 (初学一级) | 2015-05-15 10:28

@心亦: 好,那么问题可以不可以这样理解。

1、多线程,一线程、二线程。

2、插入数据,假设是一条就行,都存在并发冲突的问题,与事务无关。

3、数据库是可以限制主键重复的,也就是第二次插入直接就ERROR了。

4、那么这个逻辑哪一步是你不能接受的。

 

Insert into PrimaryID, Title values (1, "测试")   一线程

 

Insert into PrimaryID, Title values (1,"其他测试")  二线程

这样第二次插入直接就出错了。

 

5、还是说,你那个所谓的业务主键,根本就不是数据库主键,数据库是允许重复的?

 

6、如果是第5条所说的情况,那么事后补救是否可行,就是另外运行一个线程,专门检查业务数据重复,发现重复删除。

爱编程的大叔 | 园豆:30839 (高人七级) | 2015-05-15 10:33

@爱编程的大叔: 用户输入的业务主键并没有唯一约束,因为允许逻辑删除后再添加一条业务主键相同的数据

心亦 | 园豆:163 (初学一级) | 2015-05-15 10:38

@爱编程的大叔: 谢谢,有没有在sql中单线程的方法?类似于c#的lock。C#代码中不能用是因为有负载均衡,多台server同时跑。

心亦 | 园豆:163 (初学一级) | 2015-05-15 10:45

@心亦: 逻辑删除就是只做标识,不从数据库删除是吧。

那么延时处理,事后处理方式呢?

爱编程的大叔 | 园豆:30839 (高人七级) | 2015-05-15 10:46

@心亦: 负载均衡,这个说到要点了。你必须告诉别人,什么是你不能承受的,或者是不可修改的。

1、多应用服务器-单数据库。

2、如果重复插入了,后期删除会造成什么问题?

3、数据库锁定你可以看这篇文章: 

SQL Server数据库表锁定原理以及如何解除表的锁定

可以锁定表的,但不知道你是否可以承受?

爱编程的大叔 | 园豆:30839 (高人七级) | 2015-05-15 10:53

@爱编程的大叔: 是的。

这样也是一种方案。但这个发生频率不是很高,搞个线程一直跑不太好吧。

心亦 | 园豆:163 (初学一级) | 2015-05-15 10:54

@爱编程的大叔: 谢谢。嗯,还是利用数据库的锁好些

心亦 | 园豆:163 (初学一级) | 2015-05-15 10:58
其他回答(5)
0

试试园子里这篇博文中的方法:多线程重复插入数据检测SQL

dudu | 园豆:30994 (高人七级) | 2015-05-14 20:56

谢谢dudu解答。但是这篇博文中的方案二应该也建了唯一索引的,否则Try Catch就没有意义了。

支持(0) 反对(0) 心亦 | 园豆:163 (初学一级) | 2015-05-14 22:08

@心亦: 那就加唯一索引,逻辑删除怎么会违反唯一索引

支持(0) 反对(0) dudu | 园豆:30994 (高人七级) | 2015-05-14 22:26

@dudu: 一条数据被逻辑删除后,可能会再插入一条相同业务主键的数据,这样的操作应当是被允许的。但这样是违反唯一索引的。

支持(0) 反对(0) 心亦 | 园豆:163 (初学一级) | 2015-05-14 22:29

@心亦: 这个就是设计上的考虑了,基于什么样的原因,需要使用相同的业务主键?

理论上来说,就算是同样一张单据(内容相同),删除和新建的单据我们都是采用不同的主键的。

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2015-05-15 09:50

@爱编程的大叔: 这个相当于一个名字之类的东西,用户来输入的,还需要唯一。

支持(0) 反对(0) 心亦 | 园豆:163 (初学一级) | 2015-05-15 10:05

@心亦: 好吧,我知道你这是国家一级保护项目,连场景都不能说的。这样真没办法了。

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2015-05-15 10:21
0

你需要merge into命令 

吴瑞祥 | 园豆:29449 (高人七级) | 2015-05-14 22:39

这两个插入操作时在两个Transaction中的,他们对彼此是不可见的。merge into不是解决这种问题的吧。可否给个例子参考?

支持(0) 反对(0) 心亦 | 园豆:163 (初学一级) | 2015-05-14 22:54
0

1、在查询的表上建相应的索引以提高查询效率
2、在插入的目标表上先禁用索引,插入完毕后再启用。
或者
将查询出的结果集(60W)数据导入到 MDB 文件中。然后再将MDB中的数据导入目标表中。
利用导入导出工具 调用批量插入(bulkinsert)的方式 提高速度。

女孩,加油 | 园豆:1098 (小虾三级) | 2015-05-15 08:37

谢谢,不过现在不是查询速度的问题,是会插入重复数据的问题。

支持(0) 反对(0) 心亦 | 园豆:163 (初学一级) | 2015-05-15 10:07
0

业务主键冲突..你看能不能这样..在Trans insert 方法里操作一个全局变量 ,在方法的最后一条语句,将这个变量设置为true,表示方法已执行完成...当下次再调用这个方法之前,先判断全局变量是否为true,如果不..就等到为true再调用.

hexllo | 园豆:318 (菜鸟二级) | 2015-05-15 08:39
0

1、单独建个只含业务主键的表,使用唯一索引,在插入数据前先在这个表里插入主键

2、写数据时不直接操作数据库,而是把要插入的数据提交到接口,在接口程序中屏蔽重复数据

某猿 | 园豆:373 (菜鸟二级) | 2015-05-15 21:10
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册