Sql server 批量选择到varbinary中

Sql server 批量选择到varbinary中,sql-server,Sql Server,我有一个应用程序需要创建记录标识符的快照,该快照可以持久保存在数据库服务器中。我当前有一个如下所示的表: 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 (

我有一个应用程序需要创建记录标识符的快照,该快照可以持久保存在数据库服务器中。我当前有一个如下所示的表:

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字节的行存储空间,那么它很快就会累加起来

似乎更简洁的数据表示方法是只存储一个工作集id和一个varbinary列,该列按顺序包含所有记录标识符。这将避免为同一工作集中的每一行重复工作集标识符的开销,并避免存储序列号的需要,因为序列号由varbinary中的位置暗示


是否有任何合理的方法可以将INSERT查询转换为按顺序生成记录标识符的varbinary?

类似的方法可能会起作用:

-- 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);
为了额外的安全性,您可能需要先将记录ID转储到临时表中,并在Seq上使用集群主键,然后再进行连接。有序连接行为似乎相当可靠,但它不是AFAIK中记录的行为,似乎取决于执行计划中的有序假脱机或聚集索引

带有ORDERBY子句的静态游标也可以工作。它将在tempdb中具体化结果,然后对其进行迭代。考虑到这一点,不要太慢

确保使用进行增量插入,否则会导致服务器停机

或者:


为每个工作集创建单独的表。这会将行大小减少4,并且它仍然是一个常规表。

类似的方法可能会奏效:

-- 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);
为了额外的安全性,您可能需要先将记录ID转储到临时表中,并在Seq上使用集群主键,然后再进行连接。有序连接行为似乎相当可靠,但它不是AFAIK中记录的行为,似乎取决于执行计划中的有序假脱机或聚集索引

带有ORDERBY子句的静态游标也可以工作。它将在tempdb中具体化结果,然后对其进行迭代。考虑到这一点,不要太慢

确保使用进行增量插入,否则会导致服务器停机

或者:

为每个工作集创建单独的表。这会将行大小减少4,并且它仍然是一个常规表