由於涉及的人數(250萬行,看似很小的記錄)不健全過於龐大和描述的機器似乎令人印象深刻的,我不知道有多麼糟糕,這將在我的筆記本上運行。因此我創造了這個測試 '模擬' 的問題:
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分鐘我(T)生鏽的酷睿i5筆記本
- 2015年3月13日22:20:09:053 - 啓動,t_old_table ...
- 2015年3月13日22:20:09:073 - 啓動,創建docuemnt_id的...
- 2015年3月13日22:20:13:273 - ...
- 2015年3月13日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.'
這確實需要相當長的一段整理的前期,但一旦事情變得循環中,連接實際上是非常簡單和快速。事實上,整個過程不到一分鐘。
- 2015年3月13日22:26:27:030 - 創建#numbered表...
- 2015年3月13日22:26:41:307 - 轉換到t_new_table,步驟1 ...
- (500000行受影響)
- 2015年3月13日22:26:45:543 - 轉換爲t_new_table,第2步...
- (400986行(一個或多個)受影響)
- 2015年3月13日22:26:49:863 - 轉換到t_new_table,步驟3 ...
- (322042行(一個或多個)受影響)
- [。 ..
- 2015年3月13日22:27:15:713 - 轉換到t_new_table,步驟62 ...
- (1行(一個或多個)受影響)
- 2015年3月13日22:27:15:900 - 轉換爲t_new_table,步驟63 ...
- (0 row(s)affected)
- 2015年3月13日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的數據列的結果)。從這個例子我推斷出,我們正在談論的是250萬行,每個約40字節,給出的數據少於100兆(相關)。我假設你簡化了這個例子? – deroby 2015-03-13 20:39:25