代码之家  ›  专栏  ›  技术社区  ›  umbersar

将列声明为主键并向表中添加数据时为空统计信息

  •  1
  • umbersar  · 技术社区  · 6 年前

    如果我将表中的列声明为主键,则会为该列创建统计信息,但即使向表中添加了大量数据,这些统计信息也是空的。如果我在添加数据后将主键添加到able,那么stats将填充有意义的信息。为什么预先创建主键不会产生有意义的统计信息,不管我向表中添加了多少数据?

    案例1 :下面是使用主键创建表的代码:

    create table t
    (
        col1  int primary key,
        col2 int 
    )
    go
    
    --insert 150000 records into table
    insert into t (col1, col2)
        select top 150000 
            row_number() over (order by (select null)), 
            row_number() over (order by (select null)) 
        from 
            master.dbo.syscolumns 
        cross join 
            master.dbo.syscolumns as c
    

    案例2 :下面是创建表的代码,其中的主键是在将数据摄取到表中之后创建的:

    create table t
    (
        col1 int not null,
        col2 int 
    )
    go
    
    --insert 150000 records into table
    insert into t (col1, col2)
        select top 150000 
            row_number() over (order by (select null)), 
            row_number() over (order by (select null)) 
        from 
            master.dbo.syscolumns 
        cross join 
            master.dbo.syscolumns as c
    
    alter table t 
    add constraint pk_col1 primary key (col1)
    

    对于案例1,即使我试图通过对col1进行过滤来搜索索引,即使这样,统计信息也不会更新:

    select * 
    from t 
    where col1 = 4050
    

    对列进行筛选通常会创建统计信息,即使表是堆:

    create table t1
    (
        col1  int,
        col2 int 
    )
    go
    
    --insert 15000 records into table
    insert into t (col1, col2)
        select top 150000 
            row_number() over (order by (select null)), 
            row_number() over (order by (select null)) 
        from 
            master.dbo.syscolumns 
        cross join 
            master.dbo.syscolumns as c
    
    select * 
    from t1 
    where col1 = 4050
    
    1 回复  |  直到 6 年前
        1
  •  3
  •   Ruslan Tolkachev    6 年前

    好的,按照微软的说法 documentation

    查询优化器在编译查询和执行缓存查询计划之前检查过期的统计信息。在编译查询之前,查询优化器使用查询谓词中的列、表和索引视图来确定哪些统计信息可能已过期。在执行缓存查询计划之前,数据库引擎将验证查询计划是否引用了最新的统计信息。

    从SQL Server 2016(13.x)开始,在数据库兼容级别130以下,SQL Server使用一个递减的动态统计更新阈值,该阈值根据表中的行数进行调整。这是1000与当前表基数乘积的平方根。例如,如果表包含200万行,则计算结果为sqrt(1000*2000000)=44721.359。

    基本上,在索引创建/更新统计数据之前,您需要先对其运行查询。 我试过逃跑

    SELECT * 
    FROM [dbo].[t]
    WHERE col1  > 100000