代码之家  ›  专栏  ›  技术社区  ›  John Naegle

如何在SQL Server中查找未索引的外键

  •  15
  • John Naegle  · 技术社区  · 15 年前

    我有一个SQL Server 2000数据库,大约有220个表。这些表之间有许多外键关系。通过性能分析,我们发现许多这些外键关系缺少索引。我不想对性能问题作出反应,而是希望积极主动地查找所有缺少索引的外键。

    如何以编程方式确定缺少索引的外键?

    6 回复  |  直到 7 年前
        1
  •  17
  •   Quassnoi    11 年前
    SELECT  *
    FROM    sys.foreign_keys fk
    WHERE   EXISTS
            (
            SELECT  *
            FROM    sys.foreign_key_columns fkc
            WHERE   fkc.constraint_object_id = fk.object_id
                    AND NOT EXISTS
                    (
                    SELECT  *
                    FROM    sys.index_columns ic
                    WHERE   ic.object_id = fkc.parent_object_id
                            AND ic.column_id = fkc.parent_column_id
                            AND ic.index_column_id = fkc.constraint_column_id
                    )
            )
    

    我没有 SQL Server 2000 方便,但你可能需要改变 sys.foreign_key sysforeignkeys 等,如所述 here .

    此查询选择所有外键,这些外键没有覆盖构成该键的所有列的索引。

    这也支持多列外键。

    但是,如果有一个包含所有列的复合索引,但它们不是该索引中最左边的列,则返回一个误报。

    比如,如果有 FOREIGN KEY (col2, col3) 一个索引 (col1, col2, col3) ,这将返回存在一个索引,尽管此索引对此外键不可用。

        2
  •  7
  •   John Naegle    15 年前

    下面是一个适用于SQL Server 2000的答案,由同事编写:

    /*
    Description:
        This script outputs a table with all the current database un-indexed foreign keys.
    
        The table has three columns ( TableName , ColumnName, ForeignKeyName ) 
        TableName: The table containing the un-indexed foreign key
        ColumnName: The foreign key column that’s not indexed 
        ForeignKeyName: Name of foreign key witch column doesn’t have an index 
        */
    DECLARE 
        @TableName varchar(255),
        @ColumnName varchar(255),
        @ForeignKeyName sysname
    
    SET NOCOUNT ON
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    
    DECLARE FKColumns_cursor CURSOR Fast_Forward FOR
    SELECT  cu.TABLE_NAME, cu.COLUMN_NAME, cu.CONSTRAINT_NAME
    FROM    INFORMATION_SCHEMA.TABLE_CONSTRAINTS ic 
        INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu ON ic.CONSTRAINT_NAME = cu.CONSTRAINT_NAME
    WHERE   ic.CONSTRAINT_TYPE = 'FOREIGN KEY'
    
    CREATE TABLE #temp1(    
        TableName varchar(255),
        ColumnName varchar(255),
        ForeignKeyName sysname
    )
    
    OPEN FKColumns_cursor  
    FETCH NEXT FROM FKColumns_cursor INTO @TableName, @ColumnName, @ForeignKeyName
    
    WHILE @@FETCH_STATUS = 0  
    BEGIN
    
        IF ( SELECT COUNT(*)
        FROM    sysobjects o    
            INNER JOIN sysindexes x ON x.id = o.id
            INNER JOIN  syscolumns c ON o.id = c.id 
            INNER JOIN sysindexkeys xk ON c.colid = xk.colid AND o.id = xk.id AND x.indid = xk.indid
        WHERE   o.type in ('U')
            AND xk.keyno <= x.keycnt
            AND permissions(o.id, c.name) <> 0
            AND (x.status&32) = 0
            AND o.name = @TableName
            AND c.name = @ColumnName
        ) = 0
        BEGIN
            INSERT INTO #temp1 SELECT @TableName, @ColumnName, @ForeignKeyName
        END
    
    
        FETCH NEXT FROM FKColumns_cursor INTO @TableName, @ColumnName, @ForeignKeyName
    END  
    CLOSE FKColumns_cursor  
    DEALLOCATE FKColumns_cursor 
    
    SELECT * FROM #temp1 ORDER BY TableName
    
        3
  •  5
  •   trainer    13 年前

    基于上面的代码构建,以除去临时表并获取创建索引的脚本。

       /*
    Description:
    
        */
    DECLARE 
        @SchemaName varchar(255),
        @TableName varchar(255),
        @ColumnName varchar(255),
        @ForeignKeyName sysname
    
    SET NOCOUNT ON
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    
    DECLARE FKColumns_cursor CURSOR Fast_Forward FOR
    SELECT  cu.TABLE_SCHEMA, cu.TABLE_NAME, cu.COLUMN_NAME, cu.CONSTRAINT_NAME
    FROM    INFORMATION_SCHEMA.TABLE_CONSTRAINTS ic 
        INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu ON ic.CONSTRAINT_NAME = cu.CONSTRAINT_NAME
    WHERE   ic.CONSTRAINT_TYPE = 'FOREIGN KEY'
    
    CREATE TABLE #temp1(    
        SchemaName varchar(255),
        TableName varchar(255),
        ColumnName varchar(255),
        ForeignKeyName sysname
    )
    
    OPEN FKColumns_cursor  
    FETCH NEXT FROM FKColumns_cursor INTO @SchemaName,@TableName, @ColumnName, @ForeignKeyName
    
    WHILE @@FETCH_STATUS = 0  
    BEGIN
    
        IF ( SELECT COUNT(*)
        FROM        sysobjects o    
            INNER JOIN sysindexes x ON x.id = o.id
            INNER JOIN  syscolumns c ON o.id = c.id 
            INNER JOIN sysindexkeys xk ON c.colid = xk.colid AND o.id = xk.id AND x.indid = xk.indid
        WHERE       o.type in ('U')
            AND xk.keyno <= x.keycnt
            AND permissions(o.id, c.name) <> 0
            AND (x.status&32) = 0
            AND o.name = @TableName
            AND c.name = @ColumnName
        ) = 0
        BEGIN
            INSERT INTO #temp1 SELECT @SchemaName, @TableName, @ColumnName, @ForeignKeyName
        END
    
    
        FETCH NEXT FROM FKColumns_cursor INTO @SchemaName,@TableName, @ColumnName, @ForeignKeyName
    END  
    CLOSE FKColumns_cursor  
    DEALLOCATE FKColumns_cursor 
    
    SELECT 'CREATE INDEX IDX_' + ForeignKeyName + ' ON ' + SchemaName + '.' + TableName + '(' + ColumnName +')'
    FROM #temp1 
    ORDER BY TableName
    
    drop table #temp1 
    
        4
  •  1
  •   Michael Freidgeim    13 年前

    在我的岗位上 "SQL Script to create indexes for Foreign keys" 我将链接到两个实现: paul_nielsen 艾斯和 tklimczak's (login to sqlservercentral 是必需的)

        5
  •  0
  •   Community Mofi    7 年前

    首先:列出带有外键约束的列。这将有助于:

    Query to get all foreign key constraints in SQL Server 2000

    交叉比较 sysindexes syscolumns 桌子; keys 字段在 西辛德克斯 有索引中所有键的列表。

        6
  •  0
  •   user868538    7 年前

    注意:这是针对SQL Server 2005+的,但这是我找到的有关此主题的唯一问题。

    --Finds foreign keys without indexes
    --How to interpret:
    --When we delete frpm PkTable, it checks FkColumn for the PkId we are deleting.
    --So if FkTable doesn't have an index on FkColumn, then we cannot delete a row from PkTable because it is too slow.
    SELECT  rt.name as PkTableName, rc.name as PkColumnName,
    fk.name FkName, t.name as FkTableName, c.name as FkColumnName, ddps.row_count, i.name as IndexName
    FROM    sys.foreign_key_columns fkc
    inner join sys.foreign_keys fk on fkc.constraint_object_id = fk.object_id
    inner join sys.tables t on fkc.parent_object_id = t.object_id
    inner join sys.columns c on fkc.parent_object_id = c.object_id and fkc.parent_column_id = c.column_id
    inner join sys.tables rt on fkc.referenced_object_id = rt.object_id
    inner join sys.columns rc on fkc.referenced_object_id = rc.object_id and fkc.referenced_column_id = rc.column_id
    inner join sys.indexes ri on t.object_id = ri.object_id
    inner JOIN sys.dm_db_partition_stats AS ddps ON ri.OBJECT_ID = ddps.OBJECT_ID AND ri.index_id = ddps.index_id 
    left join sys.index_columns ic on ic.object_id = t.object_id and ic.column_id = c.column_id
    left join sys.indexes i on ic.object_id = i.object_id and i.index_id = ic.index_id
    where ri.index_id < 2 and i.index_id is null and ddps.row_count > 0
    order by 
    --PkTableName,
    ddps.row_count desc