SQL Server 2017 - CU25 - sp_pkeys - 错误的顺序

db2*_*222 8 sql-server sql-server-2017

我们的客户安装 CU25 后,存储过程 sp_pkeys 出现问题。如果主键有多个列,它现在可能会返回错误的顺序。

可以在代码本身中找到它。这是 2017 款 CU25 变体:

create procedure sys.sp_pkeys
(
    @table_name      sysname,
    @table_owner     sysname = null,
    @table_qualifier sysname = null
)
as
    declare @table_id           int
    -- quotename() returns up to 258 chars
    declare @full_table_name    nvarchar(517) -- 258 + 1 + 258
    
    if @table_qualifier is not null
    begin
        if db_name() <> @table_qualifier
        begin   -- If qualifier doesn't match current database
            raiserror (15250, -1,-1)
            return
        end
    end
    
    if @table_owner is null
    begin   -- If unqualified table name
        select @full_table_name = quotename(@table_name)
    end
    else
    begin   -- Qualified table name
        if @table_owner = ''
        begin   -- If empty owner name
            select @full_table_name = quotename(@table_owner)
        end
        else
        begin
            select @full_table_name = quotename(@table_owner) + '.' + quotename(@table_name)
        end
    end
    
    select @table_id = object_id(@full_table_name)
    
    select
        TABLE_QUALIFIER = convert(sysname,db_name()),
        TABLE_OWNER = convert(sysname,schema_name(o.schema_id)),
        TABLE_NAME = convert(sysname,o.name),
        COLUMN_NAME = convert(sysname,c.name),
        KEY_SEQ = (SELECT convert(smallint, index_column_id)
                             FROM sys.index_columns 
                             WHERE object_id = @table_id AND index_id = i.index_id and column_id = c.column_id),
        PK_NAME = convert(sysname,k.name)
    from
        sys.indexes i,
        sys.all_columns c,
        sys.all_objects o,
        sys.key_constraints k
    where
        o.object_id = @table_id and
        o.object_id = c.object_id and
        o.object_id = i.object_id and
        k.parent_object_id = o.object_id and 
        k.unique_index_id = i.index_id and 
        i.is_primary_key = 1 and
              c.column_id IN 
              (SELECT column_id 
              FROM sys.index_columns 
              WHERE object_id = @table_id AND index_id = i.index_id)
    order by 1, 2, 3, 5
Run Code Online (Sandbox Code Playgroud)

这是 SQL Server 2017 CU24 和 SQL Server 2019 变体:

create procedure sys.sp_pkeys  
(  
    @table_name      sysname,  
    @table_owner     sysname = null,  
    @table_qualifier sysname = null  
)  
as  
    declare @table_id           int  
    -- quotename() returns up to 258 chars  
    declare @full_table_name    nvarchar(517) -- 258 + 1 + 258  
  
    if @table_qualifier is not null  
    begin  
        if db_name() <> @table_qualifier  
        begin   -- If qualifier doesn't match current database  
            raiserror (15250, -1,-1)  
            return  
        end  
    end  
  
    if @table_owner is null  
    begin   -- If unqualified table name  
        select @full_table_name = quotename(@table_name)  
    end  
    else  
    begin   -- Qualified table name  
        if @table_owner = ''  
        begin   -- If empty owner name  
            select @full_table_name = quotename(@table_owner)  
        end  
        else  
        begin  
            select @full_table_name = quotename(@table_owner) + '.' + quotename(@table_name)  
        end  
    end  
  
    select @table_id = object_id(@full_table_name)  
  
    select  
        TABLE_QUALIFIER = convert(sysname,db_name()),  
        TABLE_OWNER = convert(sysname,schema_name(o.schema_id)),  
        TABLE_NAME = convert(sysname,o.name),  
        COLUMN_NAME = convert(sysname,c.name),  
        KEY_SEQ = convert (smallint,  
            case  
                when c.name = index_col(@full_table_name, i.index_id,  1) then 1  
                when c.name = index_col(@full_table_name, i.index_id,  2) then 2  
                when c.name = index_col(@full_table_name, i.index_id,  3) then 3  
                when c.name = index_col(@full_table_name, i.index_id,  4) then 4  
                when c.name = index_col(@full_table_name, i.index_id,  5) then 5  
                when c.name = index_col(@full_table_name, i.index_id,  6) then 6  
                when c.name = index_col(@full_table_name, i.index_id,  7) then 7  
                when c.name = index_col(@full_table_name, i.index_id,  8) then 8  
                when c.name = index_col(@full_table_name, i.index_id,  9) then 9  
                when c.name = index_col(@full_table_name, i.index_id, 10) then 10  
                when c.name = index_col(@full_table_name, i.index_id, 11) then 11  
                when c.name = index_col(@full_table_name, i.index_id, 12) then 12  
                when c.name = index_col(@full_table_name, i.index_id, 13) then 13  
                when c.name = index_col(@full_table_name, i.index_id, 14) then 14  
                when c.name = index_col(@full_table_name, i.index_id, 15) then 15  
                when c.name = index_col(@full_table_name, i.index_id, 16) then 16  
            end),  
        PK_NAME = convert(sysname,k.name)  
    from  
        sys.indexes i,  
        sys.all_columns c,  
        sys.all_objects o,  
        sys.key_constraints k  
    where  
        o.object_id = @table_id and  
        o.object_id = c.object_id and  
        o.object_id = i.object_id and  
        k.parent_object_id = o.object_id and   
        k.unique_index_id = i.index_id and   
        i.is_primary_key = 1 and  
        (c.name = index_col (@full_table_name, i.index_id,  1) or  
         c.name = index_col (@full_table_name, i.index_id,  2) or  
         c.name = index_col (@full_table_name, i.index_id,  3) or  
         c.name = index_col (@full_table_name, i.index_id,  4) or  
         c.name = index_col (@full_table_name, i.index_id,  5) or  
         c.name = index_col (@full_table_name, i.index_id,  6) or  
         c.name = index_col (@full_table_name, i.index_id,  7) or  
         c.name = index_col (@full_table_name, i.index_id,  8) or  
         c.name = index_col (@full_table_name, i.index_id,  9) or  
         c.name = index_col (@full_table_name, i.index_id, 10) or  
         c.name = index_col (@full_table_name, i.index_id, 11) or  
         c.name = index_col (@full_table_name, i.index_id, 12) or  
         c.name = index_col (@full_table_name, i.index_id, 13) or  
         c.name = index_col (@full_table_name, i.index_id, 14) or  
         c.name = index_col (@full_table_name, i.index_id, 15) or  
         c.name = index_col (@full_table_name, i.index_id, 16))  
           
    order by 1, 2, 3, 5
Run Code Online (Sandbox Code Playgroud)

关键是如何KEY_SEQ确定。如果使用第二种变体,它将正常工作。

或者,如果子选择像这样完成,那么第一个变体也可以工作:

SELECT convert(smallint, key_ordinal)
FROM sys.index_columns 
WHERE object_id = @table_id AND index_id = i.index_id and column_id = c.column_id
Run Code Online (Sandbox Code Playgroud)

因此需要使用 key_ordinal 而不是 index_column_id 。

然而,由于它是一个系统存储过程,因此似乎不可能更改它,至少在没有非常关键和不建议的步骤的情况下是不可能的。

除了降级或等待 Microsoft 修复(解决方法)之外,还有其他选择吗?

联系 Microsoft 以尽快获得修复的最佳方式是什么?

Microsoft 在CU25 的发行说明中写了有关 sp_pkeys 的更改。

向系统 sp_pkeys 添加了对 32 个键列的支持,并修复了安装 SQL Server 2017 累积更新 21 (CU21) 后出现的性能下降问题

仅供参考:与刚刚发布的CU26没有区别。

这个问题也交叉发布在 learn.microsoft.com 上

Pau*_*ite 9

除了降级或等待 Microsoft 修复(解决方法)之外,还有其他选择吗?

对于系统过程的问题没有任何支持,不。

联系 Microsoft 以尽快获得修复的最佳方式是什么?

向Microsoft 支持开立案例。

我相信如果确认原因是产品缺陷,他们会退还费用。


此问题已在SQL Server 2017 CU27SQL Server 2019 CU15中得到解决。