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 / 问题 / 239487
Accepted
Hannah Vernon
Hannah Vernon
Asked: 2019-05-31 11:25:40 +0800 CST2019-05-31 11:25:40 +0800 CST 2019-05-31 11:25:40 +0800 CST

这个索引扫描中这个 Uniq1002 列的目的是什么?

  • 772

进行以下复制:

USE tempdb;

IF OBJECT_ID(N'dbo.t', N'U') IS NOT NULL
DROP TABLE dbo.t
GO
CREATE TABLE dbo.t
(
    id int NOT NULL 
        PRIMARY KEY 
        NONCLUSTERED 
        IDENTITY(1,1)
    , col1 datetime NOT NULL
    , col2 varchar(800) NOT NULL
    , col3 tinyint NULL
    , col4 sysname NULL
);

INSERT INTO dbo.t (
      col1
    , col2
    , col3
    , col4
    ) 
SELECT TOP(100000) 
      CONVERT(datetime, 
         DATEADD(DAY, CONVERT(int, CRYPT_GEN_RANDOM(1)), '2000-01-01 00:00:00'))
    , replicate('A', 800)
    , sc2.bitpos
    , CONVERT(sysname, CHAR(65 + CRYPT_GEN_RANDOM(1) % 26) 
        + CHAR(65 + CRYPT_GEN_RANDOM(1) % 26) 
        + CHAR(65 + CRYPT_GEN_RANDOM(1) % 26))
FROM sys.syscolumns sc
    CROSS JOIN sys.syscolumns sc2;

在这里,我将聚集索引添加到一组不唯一的列上,并且是典型的单列非聚集索引:

CREATE CLUSTERED INDEX t_cx 
ON dbo.t (col1, col2, col3);

CREATE INDEX t_c1 ON dbo.t(col4); 

此查询强制 SQL Server 查找聚集索引。请原谅使用索引提示,这是获得重现的最快方法:

SELECT id
    , col1
    , col2
    , col3
FROM dbo.t aad WITH (INDEX = t_c1)
WHERE col4 = N'JSB'
    AND col1 > N'2019-05-30 00:00:00';

实际查询计划在非聚集索引扫描的输出列表中显示一个不存在的列:

在此处输入图像描述

从表面上看,这表示在非唯一聚集索引中使用的唯一标识符。是这样吗?像这样命名的列是否总是聚集索引 uniqifier?

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

2 个回答

  • Voted
  1. Best Answer
    Paul White
    2019-06-01T03:33:51+08:002019-06-01T03:33:51+08:00

    从表面上看,这表示在非唯一聚集索引中使用的唯一标识符。是这样吗?

    是的。

    这个索引扫描中这个 Uniq1002 列的目的是什么?

    非聚集索引中的每一行都必须与基表中的一行恰好相关联,这样书签查找(RID 或键)才能正常工作。此映射由“行定位器”提供。

    对于堆表,行定位器是 RID。对于集群行存储表,它是集群键(包括必要的唯一性)。

    要使计划中的Key Lookup起作用,它必须有权访问行定位器。这包括uniquifier,因此它必须由非聚集索引扫描发出。

    uniquifier存储在行的可变长度部分,因此它只在需要时(即实际存在重复键时)占用空间。

    像这样命名的列是否总是聚集索引唯一标识符?

    是的。uniquifier 列始终命名为UniqXXXX。与堆表关联的行定位器名为BmkXXXX。列存储表的行定位器名为ColStoreLocXXXX。


    观察唯一性

    可以在包含功能query_trace_column_values扩展事件的 SQL Server 版本上直接观察 uniquifier 的值。

    此未记录且不受支持的事件位于调试通道中。它是在 SQL Server 2016 中引入的,并且在 SQL Server 2017 的 CU11 附近停止工作。

    例如:

    CREATE TABLE #T (c1 integer NULL INDEX ic1 CLUSTERED, c2 integer NULL INDEX ic2 UNIQUE, c3 integer NULL);
    GO
    INSERT #T
        (c1, c2, c3)
    VALUES 
        (100, 101, 0),
        (100, 102, 1),
        (100, 103, 2);
    GO
    DBCC TRACEON (2486);
    SET STATISTICS XML ON;
    SELECT T.* FROM #T AS T WITH (INDEX(ic2));
    SET STATISTICS XML OFF;
    DBCC TRACEOFF (2486);
    GO
    DROP TABLE #T;
    

    有计划:

    计划

    它在 SQL Server 2016 上产生如下事件输出:

    事件输出

    • 9
  2. Hannah Vernon
    2019-05-31T11:42:49+08:002019-05-31T11:42:49+08:00

    为了让 SQL Server 创建非唯一聚集索引,在聚集索引的物理结构中添加了一个隐藏的“列”。该隐藏列称为 uniqifier,顾名思义,它提供了一种机制来确保聚集索引中的每一行都是唯一的。

    当您看到该列出现在查询计划中时,这是一个很好的指标,表明集群键列尚未定义为唯一的。这可能是因为已知列的组合不是唯一的。表的设计者也可能只是忘记将UNIQUE限定符添加到CREATE CLUSTERED INDEX语句中。

    事实上,如果我们使用唯一聚集索引重新创建上面的 repro,则该Uniq1002列不再出现在查询计划中:

    USE tempdb;
    
    IF OBJECT_ID(N'dbo.t', N'U') IS NOT NULL
    DROP TABLE dbo.t
    GO
    CREATE TABLE dbo.t
    (
        id int NOT NULL 
            PRIMARY KEY 
            NONCLUSTERED 
            IDENTITY(1,1)
        , col1 datetime NOT NULL
        , col2 varchar(800) NOT NULL
        , col3 int NULL
        , col4 sysname NULL
    );
    
    INSERT INTO dbo.t (
          col1
        , col2
        , col3
        , col4
        ) 
    SELECT TOP(100000) 
          CONVERT(datetime, DATEADD(DAY, CONVERT(int, CRYPT_GEN_RANDOM(1)), '2000-01-01 00:00:00'))
        , replicate('A', 800)
        , CONVERT(int, CRYPT_GEN_RANDOM(4))
        , CONVERT(sysname, CHAR(65 + CRYPT_GEN_RANDOM(1) % 26) 
            + CHAR(65 + CRYPT_GEN_RANDOM(1) % 26) 
            + CHAR(65 + CRYPT_GEN_RANDOM(1) % 26))
    FROM sys.syscolumns sc
        CROSS JOIN sys.syscolumns sc2;
    

    这是唯一的聚集索引:

    CREATE UNIQUE CLUSTERED INDEX t_cx 
    ON dbo.t (col1, col2, col3);
    
    CREATE INDEX t_c1 ON dbo.t(col4); 
    

    和查询:

    SELECT id
        , col1
        , col2
        , col3
    FROM dbo.t aad WITH (INDEX = t_c1)
    WHERE col4 = N'JSB'
        AND col1 > N'2019-05-30 00:00:00';
    

    该计划现在为非聚集索引扫描输出列显示了这一点:

    在此处输入图像描述

    创建非唯一聚集索引时,会自动添加唯一标识符。uniqifier 也被添加到每个非聚集索引中,即使您无法通过查看索引的属性或通过“编写”索引来“看到”它。

    uniqifier 是一个四字节的列,其中包含一个整数,对于插入到表中的每一行,该整数在后台自动递增。插入的第一行不需要 uniqifier;只有在第一行之后添加的行才具有 uniqifier。

    • 2

相关问题

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

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

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

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

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

Sidebar

Stats

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

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

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

    • 4 个回答
  • Marko Smith

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

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +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

热门标签

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