为什么Denali序列应该比身份列更好?
-
16-10-2019 - |
题
在他的回答中 哪个更好:身份列或生成唯一的ID值? Mrdenny说:
当SQL Denali出来时,它将支持比身份更有效的序列,但您无法创建一些更有效的东西。
我不确定。知道Oracle的 序列, ,我要么需要创建一个扳机来插入,要么将每个插入物封装到存储过程的调用中,要么祈祷我在进行临时插入时不会忘记正确使用该序列。
我怀疑序列的优势是如此明显。
解决方案
我也会在这里回答。它与内部有关 IDENTITY
和 SEQUENCE
工作。
和 IDENTITY
, ,SQL Server将值预先添加到内存中,以便容易获得。看 马丁·史密斯的答案 有关细节。当使用值时,背景过程会生成更多的值。您可以想象,这个池可能很快就用完了,将应用程序放在正在生成值的背景过程的摆放下。
和 SEQUENCE
, ,SQL Server允许您定义缓存的大小。尽管SQL Server实际上并未将值保留在缓存中,但它仅保留当前值和最高端值,这将大大减少创建值所需的IO量。
不要将缓存设置得太高,因为这将减少可以使用的数量数:如果SQL Server崩溃,则在当前高速缓存范围内指定的任何值都不会丢失。
至于行插入,只需指定列的默认值,例如:
DEFAULT (NEXT VALUE FOR Audit.EventCounter),
其他提示
自从 Itzik Ben Gan文章 被编写了硬编码的缓存大小为10 IDENTITY
似乎已经改变了。从 有关此连接项目的评论
预分配的大小基于定义身份属性的列的数据类型的大小。对于SQL Server整数列,服务器预先分配了1000个值的身份。对于BigInt数据,服务器以10000值的范围预先分配。
这 T-SQL查询 书包含下表,但强调没有记录或保证不会改变这些值。
+-----------------+-----------+
| DataType | CacheSize |
+-----------------+-----------+
| TinyInt | 10 |
| SmallInt | 100 |
| Int | 1,000 |
| BigInt, Numeric | 10,000 |
+-----------------+-----------+
这篇文章在这里 测试各种序列缓存大小和插入批量大小,并提出以下结果。
这似乎表明大型插入物 IDENTITY
表现出色 SEQUENCE
. 。但是,它不会测试1,000个尺寸的缓存尺寸,而且这些结果只是一个测试。专门查看带有各种插入物的插件的高速缓存尺寸1,000,我得到了以下结果(尝试每个批次尺寸50次,并以低于以下的μs汇总结果。
+------------+-----------+-----------+-----------+-----------+-----------+-----------+
| | Sequence | Identity |
| Batch Size | Min | Max | Avg | Min | Max | Avg |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+
| 10 | 2,994 | 7,004 | 4,002 | 3,001 | 7,005 | 4,022 |
| 100 | 3,997 | 5,005 | 4,218 | 4,001 | 5,010 | 4,238 |
| 1,000 | 6,001 | 19,013 | 7,221 | 5,982 | 8,006 | 6,709 |
| 10,000 | 26,999 | 33,022 | 28,645 | 24,015 | 34,022 | 26,114 |
| 100,000 | 189,126 | 293,340 | 205,968 | 165,109 | 234,156 | 173,391 |
| 1,000,000 | 2,208,952 | 2,344,689 | 2,269,297 | 2,058,377 | 2,191,465 | 2,098,552 |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+
对于较大的批量尺寸 IDENTITY
版本似乎一般 快点.
TSQL查询书还解释了为什么 IDENTITY
可以比序列具有性能优势。
这 IDENTITY
是表具体的 SEQUENCE
不是。如果灾难要在刷新日志缓冲区之前撞击中插入物与缓存相关的光盘写入。但是,为此 是 强制执行,因为该值可能用于任何目的 - 包括数据库之外。因此,在上面的示例中,有100万个插入和高速缓存的大小为1,000,这是另外一千个日志冲洗。
复制脚本
DECLARE @Results TABLE(
BatchCounter INT,
NumRows INT,
SequenceTime BIGINT,
IdTime BIGINT);
DECLARE @NumRows INT = 10,
@BatchCounter INT;
WHILE @NumRows <= 1000000
BEGIN
SET @BatchCounter = 0;
WHILE @BatchCounter <= 50
BEGIN
--Do inserts using Sequence
DECLARE @SequenceTimeStart DATETIME2(7) = SYSUTCDATETIME();
INSERT INTO dbo.t1_Seq1_cache_1000
(c1)
SELECT N
FROM [dbo].[TallyTable] (@NumRows)
OPTION (RECOMPILE);
DECLARE @SequenceTimeEnd DATETIME2(7) = SYSUTCDATETIME();
--Do inserts using IDENTITY
DECLARE @IdTimeStart DATETIME2(7) = SYSUTCDATETIME();
INSERT INTO dbo.t1_identity
(c1)
SELECT N
FROM [dbo].[TallyTable] (@NumRows)
OPTION (RECOMPILE);
DECLARE @IdTimeEnd DATETIME2(7) = SYSUTCDATETIME();
INSERT INTO @Results
SELECT @BatchCounter,
@NumRows,
DATEDIFF(MICROSECOND, @SequenceTimeStart, @SequenceTimeEnd) AS SequenceTime,
DATEDIFF(MICROSECOND, @IdTimeStart, @IdTimeEnd) AS IdTime;
TRUNCATE TABLE dbo.t1_identity;
TRUNCATE TABLE dbo.t1_Seq1_cache_1000;
SET @BatchCounter +=1;
END
SET @NumRows *= 10;
END
SELECT NumRows,
MIN(SequenceTime) AS MinSequenceTime,
MAX(SequenceTime) AS MaxSequenceTime,
AVG(SequenceTime) AS AvgSequenceTime,
MIN(IdTime) AS MinIdentityTime,
MAX(IdTime) AS MaxIdentityTime,
AVG(IdTime) AS AvgIdentityTime
FROM @Results
GROUP BY NumRows;