AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 1635
Accepted
bernd_k
bernd_k
Asked: 2011-03-09 12:48:42 +0800 CST2011-03-09 12:48:42 +0800 CST 2011-03-09 12:48:42 +0800 CST

为什么 Denali 序列应该比标识列表现更好?

  • 772

在他对哪个更好:标识列或生成的唯一 id 值的回答中?mrdenny 说:

当 SQL Denali 出现时,它将支持比身份更有效的序列,但您无法自己创建更高效​​的东西。

我不确定。了解 Oracle 的序列后,我必须为插入创建触发器,将每个插入封装到存储过程的调用中,或者祈祷我在执行临时插入时不要忘记正确使用序列。

我怀疑序列的优势是否如此明显。

sql-server sql-server-2012
  • 2 2 个回答
  • 4124 Views

2 个回答

  • Voted
  1. Best Answer
    mrdenny
    2011-03-09T12:56:42+08:002011-03-09T12:56:42+08:00

    我也会在这里回答。它与如何IDENTITY和SEQUENCE工作的内部结构有关。

    使用IDENTITY,SQL Server 将值预缓存到内存中,以便它们随时可用。有关详细信息,请参阅Martin Smith 的答案。随着值的使用,后台进程会生成更多值。正如您可以想象的那样,这个池可以很快用完,使应用程序受制于生成值的后台进程。

    使用SEQUENCE,SQL Server 允许您定义缓存的大小。虽然 SQL Server 实际上并没有将值保留在缓存中,它只保留当前值和顶端值,这将大大减少创建值所需的 IO 量。

    不要将缓存设置得太高,因为这会减少可以使用的数字数量:如果 SQL Server 崩溃,则在当前缓存范围中指定的任何未使用的值都将丢失。

    至于行插入,只需为列指定一个默认值,如下所示:

    DEFAULT (NEXT VALUE FOR Audit.EventCounter),
    
    • 38
  2. Martin Smith
    2012-12-28T06:56:29+08:002012-12-28T06:56:29+08:00

    自从写了 Itzik Ben Gan 文章以来,硬编码缓存大小 10IDENTITY似乎已经改变。从这个连接项目的评论

    预分配的大小基于定义标识属性的列的数据类型的大小。对于 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不是。如果灾难是在刷新日志缓冲区之前发生中间插入,则恢复的标识是否是较早的标识无关紧要,因为恢复过程也将撤消插入,因此 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;
    
    • 23

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    您如何显示在 Oracle 数据库上执行的 SQL?

    • 2 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    我可以查看在 SQL Server 数据库上运行的历史查询吗?

    • 6 个回答
  • Marko Smith

    如何在 PostgreSQL 中使用 currval() 来获取最后插入的 id?

    • 10 个回答
  • Marko Smith

    如何在 Mac OS X 上运行 psql?

    • 11 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Marko Smith

    将数组参数传递给存储过程

    • 12 个回答
  • Martin Hope
    Manuel Leduc PostgreSQL 多列唯一约束和 NULL 值 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler 什么时候应该将主键声明为非聚集的? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    BrunoLM Guid vs INT - 哪个更好作为主键? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick 如何优化大型数据库的 mysqldump? 2011-01-04 13:13:48 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve