当SQL Denali出现时,它将支持比标识更有效的序列,但是您不能自己创建更有效的序列。
我不太确定。了解Oracle的序列,我要么创建一个插入触发器,要么将每个插入封装到存储过程的调用中,要么祈祷当我进行临时插入时不要忘记正确使用序列。
我怀疑序列的优势是否如此明显。
#1 楼
我也会在这里回答。它与IDENTITY
和SEQUENCE
的工作原理有关。通过
IDENTITY
,SQL Server将值预先缓存到内存中,以便可以随时使用它们。有关详细信息,请参见Martin Smith的答案。使用值时,后台进程会生成更多值。可以想象该池很快就会用完,而应用程序则由生成值的后台进程控制。是。尽管SQL Server实际上并不将值保留在缓存中,但仅保留当前值和顶端值,这将大大减少创建值所需的IO数量。Don请不要将缓存设置得太高,因为这会减少可使用的数量:如果SQL Server崩溃,当前缓存范围中指定的所有未使用的值都将丢失。
关于行插入,只需为列指定默认值,如下所示:
DEFAULT (NEXT VALUE FOR Audit.EventCounter),
#2 楼
自从写Itzik Ben Gan文章以来,IDENTITY
的硬编码缓存大小10已更改。从此连接项的注释中,预分配的大小基于定义了identity属性的列的数据类型的大小。对于SQL Server
整数列,服务器将在1000
个值的范围内预分配标识。对于bigint数据类型,服务器在
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
不是。如果灾难是在刷新日志缓冲区之前在插入中间发生的,则恢复的身份是否为较早的身份无关紧要,因为恢复过程还将撤消插入操作,因此SQL Server不会强制在每个标识上强制刷新日志缓冲区缓存相关的光盘写入。但是,对于Sequence来说,由于值可以用于任何目的(包括数据库外部),因此必须执行。因此,在上面的示例中,具有一百万次插入并且缓存大小为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;
评论
我知道它不能回答您的问题,但是除了性能上的差异外,序列还有其他优点。例如,序列不会阻止您更新目标列,这是IDENTITY的非常不便的限制。