Что я думаю?
- Почему у вас есть дубликаты в базе данных? Чистота данных начинается с клиента на чертежной доске приложения, которая должна иметь модель данных, которая просто не допускает дублирования.
- Почему у вас есть дубликаты в базе данных? Проверка ограничений должна предотвратить это, если клиентское приложение плохо себя ведет
- Если у вас есть дубликаты, читатель должен быть готов к их обработке.
- Вы не можете обнаружить дубликаты в два этапа (посмотрите, затем отметьте), это должна быть одна атомная метка. На самом деле, вы ничего не можете сделать в базе данных в два этапа «посмотреть и пометить». Все процессы «ищите записи, а затем отмечайте найденные записи» завершаются неудачно в параллельном режиме.
- NOLOCK выдаст вам непоследовательные чтения . Записи будут отсутствовать или читать дважды. Используйте SNAPSHOT изоляцию.
- В Linq-To-SQL нет пиксельной пыли, чтобы заменить плохой дизайн.
Обновление
Рассмотрим это, например:
Постановочный стол со структурой типа:
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;
При условии, что Process A
только вставляет, эта процедура будет безопасно обрабатывать промежуточную таблицу и извлекать очищенные дубликаты. Конечно, это всего лишь скелет, настоящий процесс ETL будет иметь обработку ошибок с помощью BEGIN TRY / BEGIN CATCH и управление размером журнала транзакций с помощью пакетной обработки.