Поскольку число участвующих (2,5М строк, казалось бы, небольших записей) звучат не слишком огромна и машина описал казалось впечатляющим, я задавался вопросом, как плохо это будет работать на моем ноутбуке. Таким образом, я создал этот тест, который 'имитирует' вопрос:
IF DB_ID('test') IS NULL CREATE DATABASE test
GO
USE test
GO
SET NOCOUNT ON
PRINT Convert(varchar, current_timestamp, 113) + ' - starting up, creating t_old_table...'
IF OBJECT_ID('t_old_table') IS NOT NULL DROP TABLE t_old_table
GO
CREATE TABLE t_old_table (row_id int IDENTITY(1, 1) PRIMARY KEY,
document_id nvarchar(50) NOT NULL,
parsed_codes nvarchar(50) NOT NULL)
GO
PRINT Convert(varchar, current_timestamp, 113) + ' - starting up, creating docuemnt_id''s...'
-- create unique document_id's first
DECLARE @counter int = 1,
@target int = 500000,
@block int = 10000
INSERT t_old_table (document_id, parsed_codes) VALUES (Reverse(Convert(nvarchar(50), NewID())), Convert(nvarchar(50), BINARY_CHECKSUM(NewID())))
WHILE @counter < @target
BEGIN
INSERT t_old_table (document_id, parsed_codes)
SELECT TOP (CASE WHEN @counter + @block > @target THEN @target - @counter ELSE @block END)
Reverse(Convert(nvarchar(50), NewID())),
Convert(nvarchar(50), BINARY_CHECKSUM(NewID()))
FROM t_old_table
SELECT @counter = @counter + @@ROWCOUNT
END
PRINT Convert(varchar, current_timestamp, 113) + ' - starting up, adding parsed codes...'
-- add parsed-codes to existing document_id's
SELECT @target = @target * 5
WHILE @counter < @target
BEGIN
INSERT t_old_table (document_id, parsed_codes)
SELECT TOP (CASE WHEN @counter + @block > @target THEN @target - @counter ELSE @block END)
document_id,
Convert(nvarchar(50), BINARY_CHECKSUM(NewID()))
FROM t_old_table
ORDER BY NewID() -- some document_id's will have more, some will have less
SELECT @counter = @counter + @@ROWCOUNT
END
UPDATE STATISTICS t_old_table
PRINT Convert(varchar, current_timestamp, 113) + ' - Creating t_new_table...'
GO
IF OBJECT_ID('t_new_table') IS NOT NULL DROP TABLE t_new_table
GO
CREATE TABLE t_new_table (document_id nvarchar(50) NOT NULL PRIMARY KEY,
parsed_codes_list nvarchar(max) NOT NULL)
GO
Запуск этого потребовалось около 6 минут на мой (т) ноутбук ржавый i5
- 13 Mar +2015 22: 20: 09: 053 - запуск, t_old_table ...
- 13 марта 2015 г. 22: 20: 09: 073 - запуск, создание документа ...
- 13 марта 2015 г. 22: 20: 13: 273 - запуск, добавление разобранных кодов ...
- 13 мар 2015 22: 26: 27: 023 - Создание t_new_tabl д ...
Далее я принял следующий подход:
PRINT Convert(varchar, current_timestamp, 113) + ' - Creating #numbered table...'
-- step 1, make temp-table that holds 'correct' order
IF OBJECT_ID('tempdb..#numbered') IS NOT NULL DROP TABLE #numbered
GO
SELECT document_id,
parsed_codes,
order_nbr = ROW_NUMBER() OVER (PARTITION BY document_id ORDER BY parsed_codes)
INTO #numbered
FROM t_old_table
WHERE 1 = 2
CREATE UNIQUE CLUSTERED INDEX uq0 ON #numbered (order_nbr, document_id)
INSERT #numbered
SELECT document_id,
parsed_codes,
order_nbr = ROW_NUMBER() OVER (PARTITION BY document_id ORDER BY parsed_codes)
FROM t_old_table
GO
-- extract parsed codes
DECLARE @nbr int = 1,
@rowcount int
SET NOCOUNT OFF
PRINT Convert(varchar, current_timestamp, 113) + ' - Converting to t_new_table, step ' + convert(varchar, @nbr) + '...'
INSERT t_new_table (document_id, parsed_codes_list)
SELECT document_id, parsed_codes
FROM #numbered
WHERE order_nbr = @nbr
SELECT @rowcount = @@ROWCOUNT
UPDATE STATISTICS t_new_table
WHILE @rowcount > 0
BEGIN
SELECT @nbr = @nbr + 1
PRINT Convert(varchar, current_timestamp, 113) + ' - Converting to t_new_table, step ' + convert(varchar, @nbr) + '...'
UPDATE t_new_table
SET parsed_codes_list = parsed_codes_list + ';' + n.parsed_codes
FROM t_new_table
JOIN #numbered n
ON n.document_id = t_new_table.document_id
AND n.order_nbr = @nbr
SELECT @rowcount = @@ROWCOUNT
END
GO
-- all done
PRINT Convert(varchar, current_timestamp, 113) + ' - All done.'
Это займет некоторое сортировкой вверх-вперед, но как только вещи получить зацикливание, стыки на самом деле довольно просто и быстро. Фактически, все это продолжалось менее минуты.
- 13 Mar 2015 22: 26: 27: 030 - Создание #numbered таблицы ...
- 13 марта 2015 22: 26: 41: 307 - Преобразование t_new_table, шаг 1 ...
- (Затронуто 500000 строк)
- 13 Mar 2015 22: 26: 45: 543 - Преобразование в t_new_table, шаг 2 ...
- (400986 строк (ы) пострадавших)
- 13 марта 2015 22: 26: 49: 863 - Преобразование в t_new_table, шаг 3 ...
- (+322042 строку (ы) пострадавших)
- [. ..]
- 13 марта 2015 22: 27: 15: 713 - Преобразование в t_new_table, шаг 62 ...
- (1 строку (ы) пострадавших)
- 13 марта 2015 22: 27: 15: 900 - Преобразование в t_new_table, этап 63 ...
- (0 ряд (-ых) затронутых)
- 13 марта 2015 г. 22: 27: 15: 940 - Все сделано.
Поскольку я не могу поверить, что мой ноутбук/решение в том, что гораздо быстрее, чем то, что у вас есть, я побежал ваш запрос
SELECT
t1.document_id as document_id,
Stuff((SELECT '; ' + CONVERT(NVARCHAR(max), parsed_codes)
FROM t_old_table t2
WHERE t2.document_id = t1.document_id
FOR XML PATH('')), 1, 2, '') as [New_parsed_codes]
INTO dbo.[New_Table]
FROM t_old_table t1
GROUP BY t1.document_id
и он побежал за 40 секунд.
Это заставляет меня поверить, что вам нужно будет объяснить немного дальше ситуацию (размер имеет значение =), поэтому мы можем лучше понять, где тратится время; или у вас есть проблема с оборудованием ...
Насколько велика таблица «байт-мудрый»? (например, результат столбца данных sp_spaceused). Из примера «вывести» мы говорим о 2,5 М строк порядка 40 байт каждый, давая менее 100 МБ (релевантных) данных. Я предполагаю, что вы упростили пример? – deroby