SQL Server: почему эта логика не работает при чанкинге по вставкам?
Товарищи Техники--
У меня здесь происходит бесконечная петля. Почему @@ rowcount никогда не возвращается в 0? Я не должен понимать, что на самом деле делает @@ rowcount, или я устанавливаю значение не в том месте. Я думаю, что значение должно уменьшаться на каждом проходе, пока я не достигну нуля.
DECLARE @ChunkSize int = 250000;
WHILE @ChunkSize <> 0
BEGIN
BEGIN TRANSACTION
INSERT TableName
(col1,col2)
SELECT TOP (@ChunkSize)
col1,col2
FROM TableName2
COMMIT TRANSACTION;
SET @ChunkSize = @@ROWCOUNT
END -- transaction block
END -- while-loop block
3 ответа
Внедренное решение
В конце я решил прокачать SQL через SSIS, где я мог соответственно установить размер пакета коммита. Если бы я не выбрал нужный маршрут, мне пришлось бы следовать предложению @scsimon и в основном вести таблицу отслеживания для завершенных записей и оставленных для циклического просмотра записей.
Я не уверен по тому, что вы опубликовали, как вы собираетесь ловить строки, которые вы еще не вставили. Если вы этого не сделаете, конечно, это будет бесконечный цикл. Вот способ использования тестовых данных - но, естественно, вы захотите основывать его на PK или другом уникальном столбце. Возможно, вы просто оставили эту часть, или я что-то упустил все вместе. Мне просто интересно, каков ваш окончательный код для вашей порции и логика, стоящая за ней, так что это ответ и запрос.
if object_id('tempdb..#source') is not null drop table #source
if object_id('tempdb..#destination') is not null drop table #destination
create table #source(c1 int, c2 int)
create table #destination (c1 int, c2 int)
insert into #source (c1,c2) values
(1,1),
(2,1),
(3,1),
(4,1),
(5,1),
(6,1),
(7,1),
(8,1),
(9,1),
(10,1),
(11,1),
(12,1)
DECLARE @ChunkSize int = 2;
WHILE @ChunkSize <> 0
BEGIN
INSERT INTO #destination (c1,c2)
SELECT TOP (@ChunkSize) c1,c2 FROM #source WHERE c1 NOT IN (SELECT DISTINCT c1 FROM #destination) ORDER BY ROW_NUMBER() OVER (ORDER BY C1)
SET @ChunkSize = @@ROWCOUNT
--SELECT @ChunkSize
END
select * from #source
select * from #destination
Ничего не происходит, потому что вы устанавливаете chunksize для себя, даже не смотря на то, что вы уже вставили. Используя ваш пример, @Chunksize = 250000
, Сначала выберите выполняет SELECT TOP 250000
и возвращает (предположительно) 250000 строк. Затем вы используете @@RowCount
обновлять @Chunksize
, но возвращаемое число строк будет 250000, поэтому вы просто установите его снова на 250000. Это может быть хорошо, за исключением того, что число никогда не изменится без исключения уже вставленных вами строк - вы будете вставлять те же 250000 строк снова и снова.
Вам нужно что-то вроде NOT EXISTS
чтобы отфильтровать уже вставленные строки:
DECLARE @ChunkSize int = 250000;
WHILE @ChunkSize > 0
BEGIN
BEGIN TRANSACTION
INSERT INTO TableName
(col1,col2)
SELECT TOP (@ChunkSize)
col1,col2
FROM TableName2 T2
WHERE NOT EXISTS (SELECT *
FROM TableName T
WHERE T.Col1 = T2.Col1
AND T.Col2 = T2.Col2)
SET @ChunkSize = @@ROWCOUNT
PRINT CONVERT(nvarchar(10),@ChunkSize) + ' Rows Inserted.';
COMMIT TRANSACTION
END -- while-loop block