обход дублирующей записи первичного ключа до следующей вставки - PullRequest
4 голосов
/ 26 января 2010

странный вопрос. я вставляю 10 000 записей или около того в таблицу, и первичный ключ не является полем идентификации. поэтому при вставке всех 10 000, если некоторые дубликаты, есть ли способ перейти к следующей записи в SQL Server вставке и убедиться, что не дубликаты входят? мне действительно все равно, что дубликаты не вставляются.

Ответы [ 4 ]

8 голосов
/ 26 января 2010

Используйте опцию «Игнорировать дубликат ключа».

Самый простой способ сделать это - удалить первичный ключ в SQL Server Management Studio.

Затем создайте новый индекс типа «Индекс», установите для параметра «Уникальный» значение «Да» и для параметра «Игнорировать повторяющиеся ключи» значение «Да». Затем вставьте свои записи. Он вставит их все, кроме дубликатов. Когда вы закончите, вы можете удалить этот индекс и воссоздать ваш первичный ключ.

Если вам нужен метод TSQL, см. Параметр IGNORE_DUP_KEY в вызове CREATE INDEX:

CREATE INDEX (Transact-SQL)

РЕДАКТИРОВАТЬ:

Другим способом было бы использовать LEFT JOIN между вашей исходной таблицей и записями, которые вы собираетесь вставить, и предложение GROUP BY, только вставляя записи, которых нет в вашем источнике. GROUP BY удалит ваши дубликаты в новых записях.

5 голосов
/ 26 января 2010

вам нужно определить ваш первичный ключ, чтобы игнорировать дубликаты:

CREATE TABLE [dbo].[t2](
      [n] [int] NOT NULL,
PRIMARY KEY CLUSTERED
(
      [n] ASC
)WITH (IGNORE_DUP_KEY = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

Использование этой опции может снизить производительность:

Если в ваших данных небольшой процент дубликатов, IGNORE_DUP_KEY может ускорить вставку. Для больших количеств дубликатов IGNORE_DUP_KEY может значительно замедлить их. Я установил две таблицы, вычеркнув все несущественные детали, следующим образом:

CREATE TABLE t1(n INT NOT NULL PRIMARY KEY)
GO
CREATE TABLE [dbo].[t2](
      [n] [int] NOT NULL,
PRIMARY KEY CLUSTERED
(
      [n] ASC
)WITH (IGNORE_DUP_KEY = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

Если во входных данных не было дубликатов, производительность обеих вставок была одинаковой:

INSERT t1(n)
SELECT n FROM dbo.Numbers

INSERT t2(n)
SELECT n FROM dbo.Numbers

(Обратите внимание, что dbo. Numbers содержит 1 миллион строк.) Конечно, я всегда усекал обе таблицы между своими тестами.

Если входящие данные содержали 1% дубликатов, вставка с IGNORE_DUP_KEY последовательно выполнялась примерно на 5% быстрее:

INSERT t1(n)
SELECT DISTINCT n FROM(
SELECT n FROM dbo.Numbers
UNION ALL
SELECT n FROM dbo.Numbers WHERE n <10000
) AS t

INSERT t2(n)
SELECT n FROM dbo.Numbers
UNION ALL
SELECT n FROM dbo.Numbers WHERE n <10000

С другой стороны, если входящие данные имели 100% дубликатов, вставка с IGNORE_DUP_KEY последовательно выполнялась как минимум на 300% медленнее, как для большого набора из 2 миллионов строк:

INSERT t1(n)
SELECT DISTINCT n FROM(
SELECT n FROM dbo.Numbers
UNION ALL
SELECT n FROM dbo.Numbers
) AS t

INSERT t2(n)
SELECT n FROM dbo.Numbers
UNION ALL
SELECT n FROM dbo.Numbers

Как и для меньшего набора строк по 200К:

INSERT t1(n)
SELECT DISTINCT n FROM(
SELECT n FROM dbo.Numbers WHERE n<100000
UNION ALL
SELECT n FROM dbo.Numbers WHERE n<100000
) AS t

INSERT t2(n)
SELECT n FROM dbo.Numbers WHERE n<100000
UNION ALL
SELECT n FROM dbo.Numbers WHERE n<100000 

В целом, я решил не использовать IGNORE_DUP_KEY в моем конкретном случае. Я решил, что небольшая экономия при небольшом количестве дубликатов не оправдывает риск значительного падения производительности при больших объемах дублирующихся данных.

2 голосов
/ 26 января 2010

В этом примере запроса пропускаются повторяющиеся строки по PK1:

INSERT INTO Dest (PK1, Field2)
SELECT s.PK1, s.F2
FROM Source s
WHERE
(
    SELECT TOP 1 d.PK1
    FROM Dest d
    WHERE d.PK1 = s.PK1
) IS NULL
0 голосов
/ 26 января 2010

На ум приходит несколько способов, так как я не знаю, какой механизм вы используете для вставки.

1) Массово загрузите все записи в новую пустую таблицу, затем запустите INSERT в реальной таблице из той промежуточной таблицы, где записи еще не существует в основной таблице. например,

INSERT MyRealTable (PKField, Field1)
SELECT x.PKField, x.Field1
FROM MyStagingTable x
    LEFT JOIN MyRealTable r ON x.PKField = r.PKField
WHERE r.PKField IS NULL

2) обернуть каждую вставку в блок TRY ... CATCH , чтобы проглотить ошибку ограничения PK в случае ее возникновения (если вы используете SQL 2005 или более позднюю версию).

...