2010-08-24 3 views
2

У меня есть приложение, которое должно создать моментальный снимок идентификаторов записей, которые могут сохраняться на сервере базы данных. Я в настоящее время есть таблица, которая выглядит следующим образом:bulk-select в varbinary

CREATE TABLE Workset (
    Workset_id int, 
    Sequence int, 
    Record_id int 
) 

который я вставить используя что-то вроде:

INSERT INTO WorkSet (Workset_id, Sequence, Record_id) 
SELECT TOP 100 
    @Workset_id, 
    ROW_NUMBER() OVER (
    ORDER BY -- this may be a complex ordering clause 
), 
    Record_id  
FROM SalesRecords 
-- WHERE some conditions are met 

Позже, я могу запросить записи идентификатора конкретной записи в рабочем наборе идентификатор и номер строки

SELECT SalesRecords.* FROM SalesRecords 
JOIN WorkSet ON WorkSet.Record_Id = SalesRecords.Record_id 
WHERE Workset_id = @Workset_id AND Sequence = @Sequence 

проблема с этим состоит в том, что, как снимок получает большое количество данных, что я должен написать в данный быстро растет рабочий набор. Было бы необычно иметь рабочий набор в миллионах записей, и если каждый из этих элементов требует 12 байтов хранения строк, он быстро складывается.

Похоже, что более компактный способ представления данных состоял в том, чтобы хранить просто Workset_id и столбцы varbinary, содержащие все идентификаторы записей в порядке последовательности. Это позволит избежать накладных расходов на повторение идентификатора рабочего набора для каждой строки на одном и том же рабочем наборе и избегать необходимости хранить порядковые номера (поскольку они подразумеваются положением в varbinary).

Есть ли разумный способ, чтобы я мог преобразовать свой запрос INSERT во что-то, что генерирует varbinary идентификаторов записи по порядку?

ответ

0

Нечто подобное может работать:

-- create a generic numbers table for demonstration purposes and populate it 
IF OBJECT_ID('tempdb..#numbers') IS NOT NULL DROP TABLE #numbers; 
CREATE TABLE #numbers (number INT PRIMARY KEY); 
WITH Ten AS (SELECT * FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) a (number)) 
INSERT #numbers (number) SELECT a.number + b.number*10 + c.number*100 + d.number*1000 + e.number*10000 
FROM Ten a, Ten b, Ten c, Ten d, Ten e; 

-- concatenate the ints in a particular order 
DECLARE @varbinary VARBINARY(MAX); 
SET @varbinary = 0x; 
WITH Ids AS (SELECT number AS Id FROM #numbers) 
SELECT @varbinary += convert(BINARY(4),Id) 
FROM (
    SELECT Id, Seq = ROW_number() OVER (ORDER BY NEWID()) 
    FROM Ids WHERE Id BETWEEN 1000 AND 1099 
) a 
ORDER BY Seq; 

--split them back out by position 
;WITH Positions AS (SELECT number AS Position FROM #numbers) 
SELECT Position, Id = CONVERT(INT,substring(@varbinary,Position*4+1,4)) 
FROM Positions WHERE Position*4 < DATALENGTH(@varbinary); 

Вы можете сбросить записи идентификаторов в временную таблицу первых, с кластерным первичного ключа на послед до конкатенации, для дополнительной безопасности. Приведенное поведение конкатенации выглядит достаточно надежным, но это не документированное поведение AFAIK и, по-видимому, зависит от упорядоченного буфера или кластерного индекса в плане выполнения.

Статический указатель w/order by clause также будет работать. Он будет реализовывать результаты в tempdb, а затем перебирать их. Не слишком медленно, учитывая.

Обязательно используйте .WRITE clause of the UPDATE statement для инкрементных «вставок», или вы снимете сервер.

Альтернативно:

Создайте отдельную таблицу для каждого рабочего набора. Это уменьшает размер вашей строки на 4, и это по-прежнему регулярная таблица.