我有一个应用程序需要创建记录标识符的快照,这些记录标识符可以保存在数据库服务器中。我目前有一个看起来像这样的表:
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 :(得分: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);
为了更加安全,您可能希望首先将记录ID转储到临时表中,并在Seq之前使用Seq上的群集主键进行连接。有序的连接行为似乎相当可靠,但它没有记录行为AFAIK,并且似乎依赖于执行计划中的有序假脱机或聚簇索引。
带有order by子句的静态游标也可以。它将在tempdb中实现结果,然后迭代它们。考虑到,不要太慢。
确保使用.WRITE
clause of the UPDATE statement进行增量“插入”,否则您将关闭服务器。
<强>替代地强>:
为每个WorkSet创建一个单独的表。这会将行大小减少4,并且它仍然是常规表。