我在名为“A”的表格中有很多信息。名为“B”的表格为空。
我从表A得到500行,这些行不在表“B”中:
SELECT TOP 500 * FROM A WHERE
NOT EXISTS (
SELECT * FROM B WHERE
(
A.id1=B.id1 AND A.id2=B.id2
)
)
一切都运作良好,但我有一个问题。
我有一个Web应用程序,它调用该SQL查询。想象一下,200个人一起调用我的应用程序,名为“B”的表中将存在重复项。播种如何锁定这些行?
这是对的吗?
SELECT TOP 500 * FROM A WITH (ROWLOCK) WHERE
NOT EXISTS (
SELECT * FROM B WITH (ROWLOCK) WHERE
(
A.id1=B.id1 AND A.id2=B.id2
)
)
更清楚:
想象一下,当你打开我的web应用程序,页面调用(例如Servlet或PHP)SQL查询时。
如果很多人一起打开我的应用程序,则存在线程问题。而open查询是将数据写入名为B的表,另一个查询并行执行相同的操作。
线程问题:当一个线程读取500行时,另一个线程可能会读取相同的数据,因为此时第一个线程仍在写入数据但尚未完成。
线程1读取表“A”中的数据: 1,2,3,4,5,6,7 ... 500
线程1将该数据打包到名为“B”的表中: 1,2,3,4,5,6,7,... 495
线程1未完成,线程2读取表“a”中的数据: 496,497 .. 500,...... 995
线程2写 496,497 .. 500,...... 995
然后再次线程1写入数据
495 .. 500
例如
答案 0 :(得分:1)
一个行锁只会锁定该行 转移到tablelock会影响性能。
我会在InProcess的A中添加一个状态列 然后在事务标记中为true。
所以你的查询也会有A.InProcess = false。
答案 1 :(得分:0)
我需要指出的是,您发布的查询实际上并没有向表B写任何内容。
话虽如此,如果您只想锁定表A中正在处理的行,我建议在表中添加一个状态列,并使用类似于以下内容的存储过程。
DECLARE @Results TABLE
(
id1 int NOT NULL,
id2 int NOT NULL --Assuming these are ints
)
UPDATE TOP (500) A with (ROWLOCK, READPAST)
SET [Status] = 'InProcess'
OUTPUT inserted.id1,
inserted.id2
INTO @Results
WHERE [Status] <> 'InProcess'
SELECT * FROM @Results temp
INNER JOIN A
ON A.id1 = temp.id1 AND A.id2=temp.id2
当我有多个工作人员来到一张桌子寻找要完成的任务时,我使用过这种方法。
这里的关键点是:
这里有很多事情,也许你不需要这一切,但这是我发现在防止竞争条件时给予我高并发性的方法。