我有一個包含大約220個表的SQL Server 2000數據庫。這些表具有它們之間的數字外鍵關係。通過性能分析,我們發現一些這些外鍵關係是缺少索引。我不希望被性能問題所困擾,而是想積極主動地找到所有缺少索引的外鍵。如何在SQL Server中查找未索引的外鍵
如何以編程方式確定哪些外鍵缺少索引?
我有一個包含大約220個表的SQL Server 2000數據庫。這些表具有它們之間的數字外鍵關係。通過性能分析,我們發現一些這些外鍵關係是缺少索引。我不希望被性能問題所困擾,而是想積極主動地找到所有缺少索引的外鍵。如何在SQL Server中查找未索引的外鍵
如何以編程方式確定哪些外鍵缺少索引?
這裏是由一位同事撰寫的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
首先:列出具有外鍵約束的列。這將有助於:
Query to get all foreign key constraints in SQL Server 2000
交叉比較sysindexes
和syscolumns
表; sysindexes
中的keys
字段具有索引中所有鍵的列表。
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)
索引,這將返回有,儘管這一指數是不能用於本外鍵索引。
這可能是我想要的SQL Server 2005和更高版本,但我沒有測試過它。當我將其轉換時,我會發布SQL Server 2000等價物。 – 2009-09-10 17:30:56
我還會在NOT EXISTS中使用'AND ic.index_column_id = fkc.constraint_column_id'來確保索引也處於正確的索引鍵列順序。否則,正是我每天都在使用的東西 – gbn 2013-04-25 09:05:30
建在上面的代碼刪除臨時表,並得到腳本來創建索引。
/*
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
注:這是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
缺失或很少使用?這篇文章是爲2005年,但可以幫助:http://blogs.msdn.com/sqlcat/archive/2006/02/13/531339.aspx – 2009-09-10 15:57:59
缺少。很少使用的是另一個有趣的性能優化,但不是我在這裏感興趣的。 – 2009-09-10 16:01:38