【问题标题】:Do statistics referencing a column prevent that column from being dropped?引用列的统计信息是否会阻止删除该列?
【发布时间】:2011-10-31 16:31:03
【问题描述】:

我正在尝试一个非常简单的drop column 声明:

alter table MyTable drop column MyColumn

并收到几个错误

消息 5074,第 16 级,状态 1,第 1 行
统计信息“_dta_stat_1268251623_3_2”取决于列“MyColumn”。

最后是

消息 4922,第 16 级,状态 9,第 1 行
ALTER TABLE DROP COLUMN MyColumn 失败,因为一个或多个对象访问此列。

我认为统计数据不会阻止删除列。他们有吗?如果是这样,由于这些显然是自动创建的统计信息,我不能依赖于同一数据库的多个副本中相同的名称,那么如何将所有这些统计信息放在升级脚本中以在不同的数据库上执行?

【问题讨论】:

    标签: sql-server sql-server-2005 ddl


    【解决方案1】:

    JNK 答案中提出的代码不起作用,但想法很好。如果您想删除所有用户创建的统计信息,这是我测试过的解决方案:

    DECLARE @sql NVARCHAR(MAX)
    
    DECLARE statCursor CURSOR FOR 
    SELECT 
        'DROP STATISTICS ' + QUOTENAME(SCHEMA_NAME(t.schema_id)) 
                            + '.' + QUOTENAME(t.name) 
                            + '.' + QUOTENAME(st.name) AS sql
    FROM
        sys.stats AS st 
        INNER JOIN sys.tables AS t
            ON st.object_id = t.object_id
    WHERE
        st.user_created = 1
    ORDER BY 1;
    
    OPEN statCursor;
    
    FETCH NEXT FROM statCursor INTO @sql
    WHILE @@FETCH_STATUS = 0  
    BEGIN  
        PRINT @sql
        EXEC sp_executesql @sql
        FETCH NEXT FROM statCursor INTO @sql
    END  
    CLOSE statCursor  
    DEALLOCATE statCursor
    

    【讨论】:

    • 您确实是正确的 JNK 答案在 sql server 2008 上根本不起作用(查询从未完成)将您的示例切换为使用 sys.columns
    • 如何通过数据库而不是所有数据库来限制这一点
    • 查询只适用于当前数据库
    【解决方案2】:

    我见过的所有自动生成的统计信息要么具有它们所代表的索引的名称,要么以 WA_Sys_ 之类的开头。

    您是否 100% 确定这不是某人设置的一组自定义统计信息?

    检查一下:

    select *
    FROM sys.stats WHERE name = '_dta_stat_1268251623_3_2'
    

    ...看看user_created 字段的含义。

    每条评论:

    这是未经测试的,但您可以尝试以下方法:

    exec sp_MSforeachdb '
    use ?
    
    DECLARE @SQL varchar(max) = ''''
    
    select @SQL = @SQL + ''DROP STATISTICS '' + OBJECT_NAME(c.object_id) + ''.'' + s.name + CHAR(10) + CHAR(13)
    from sys.stats s
    INNER JOIN sys.stats_columns sc
    ON sc.stats_id = s.stats_id
    INNER JOIN sys.columns c
    ON c.column_id = sc.column_id
    WHERE c.name = ''ClaimNbr''
    --and s.user_created = 1
    
    PRINT @SQL'
    

    如果看起来不错,请将 PRINT 更改为 EXEC

    sp_msforeachdb 是背景中的光标,但您可以将其余逻辑作为一个集合来执行。

    【讨论】:

    • 你是对的!我相信这些是由数据库引擎优化顾问创建的。您能否推荐一种方法来删除所有引用列的用户创建的统计信息?
    • 您可以使用其他系统视图sys.stats_columnssys.columns 来获取/加入该信息。
    • 是的,我必须使用你的旧光标来删除它们。谢谢。
    • @Daniel - 不需要游标,但对于少量的执行,你可能会运行它可能无关紧要。
    • 如何避免光标?是否有另一种方法可以在单个语句中删除所有引用列的用户创建的统计信息?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 1970-01-01
    • 2018-07-26
    • 2013-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多