我有两个进程可以处理同一个表中的数据。
每天一个进程逐个插入(纯ADO.NET),目标表中大约有20000条记录。
第二个进程调用(定期,每15分钟)一个存储过程
有时这两个进程重叠(由于数据处理的延迟),我怀疑如果第一个进程在第二个进程介于1和2之间时插入新记录,那么记录将被标记为“ToBeCopied”而没有经过重复筛选。
这意味着现在存储过程正在返回一些重复项。
这是我的理论,但在实践中我无法复制它......
我正在使用LINQ to SQL来插入重复项(每秒40-50左右)并且在运行时我手动调用存储过程并存储其结果。
当存储过程正在运行时,插入暂停......这样最后没有重复项使其进入最终结果集。
我想知道LINQ to SQL或SQL Server是否具有阻止并发的默认机制,并且在选择或更新发生时暂停插入。
您怎么看?
编辑1:
'重复'不是相同的行。鉴于这些记录所代表的业务/逻辑实体,它们是“等效的”。每行都有一个唯一的主键。
P.S。使用NOLOCK选择结果集。尝试在SQL Server 2008上重现。据称在SQL Server 2005上会出现问题。
答案 0 :(得分:3)
我怎么想?
更新
例如考虑这个:
具有以下结构的临时表:
CREATE TABLE T1 (
id INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
date DATETIME NOT NULL DEFAULT GETDATE(),
data1 INT NULL,
data2 INT NULL,
data3 INT NULL);
进程A
正在暂时插入此表。它会进行任何验证,它只是将原始记录转储到:
INSERT INTO T1 (data1, data2, data3) VALUES (1,2,3);
INSERT INTO T1 (data1, data2, data3) VALUES (2,1,4);
INSERT INTO T1 (data1, data2, data3) VALUES (2,2,3);
...
INSERT INTO T1 (data1, data2, data3) VALUES (1,2,3);
INSERT INTO T1 (data1, data2, data3) VALUES (2,2,3);
...
INSERT INTO T1 (data1, data2, data3) VALUES (2,1,4);
...
进程B
的任务是提取此临时表并将已清理的数据移动到表T2中。它必须删除重复项,这些重复项按业务规则表示data1,data2和data3中具有相同值的记录。在一组重复项中,只应保留date
的第一条记录:
set transaction isolation snapshot;
declare @maxid int;
begin transaction
-- Snap the current max (ID)
--
select @maxid = MAX(id) from T1;
-- Extract the cleaned rows into T2 using ROW_NUMBER() to
-- filter out duplicates
--
with cte as (
SELECT date, data1, data2, datta3,
ROW_NUMBER() OVER
(PARTITION BY data1, data2, data3 ORDER BY date) as rn
FROM T1
WHERE id <= @maxid)
MERGE INTO T2
USING (
SELECT date, data1, data2, data3
FROM cte
WHERE rn = 1
) s ON s.data1 = T2.data1
AND s.data2 = T2.data2
AND s.data3 = T2.data3
WHEN NOT MATCHED BY TARGET
THEN INSERT (date, data1, data2, data3)
VALUES (s.date, s.data1, s.data2, s.data3);
-- Delete the processed row up to @maxid
--
DELETE FROM T1
WHERE id <= @maxid;
COMMIT;
假设只插入进程A
,此过程将安全地处理登台表并提取已清理的重复项。当然,这只是一个框架,一个真正的ETL过程将通过BEGIN TRY / BEGIN CATCH进行错误处理,并通过批处理控制事务日志大小。
答案 1 :(得分:0)
您何时在数据上下文中调用submit?我相信这是在交易中发生的。
关于你的问题,你所说的听起来似乎有道理 - 你可能更有意义的是你加载到临时表(如果它很慢)然后做一个
SELECT * FROM StagingTable INTO ProductionTable
一旦你的装载完成了吗?