SQL Server 性能优化之——重复索引
2013-06-17 09:18
429 查看
原文/article/5325299.html
阅读导航
1.概述
2.什么是重复索引
3.查找重复索引
4.删除重复索引
5.总结
1.概述
很多人都知道索引在数据库上的是有利有弊的。像其他主流商业数据库一样SQLServer允许在一个列上重复创建索引。因为SQLServer没有限制创建重复索引的数量,只是限制数据库的一个表上最多可以创建999重复索引,所以这就增加了数据库中存在重复索引的可能性。表的列上存在重复索引的话,可能会明显的损害数据库性能,因为SQLServer必须分别维护每一个重复索引。此外,SQLServer优化查询语句时,查询优化器也会考虑这个问题,这就导致一系列性能问题。要理解什么事实重复索引、怎么样找到它们、怎么样移除它们。
2.什么是重复索引
首先假设有一个表Test_Table有四个列(Col1,Col2,Col3,Col4)
1)在主键列上创建不同类型的索引
2)在非主键列上创建不同顺序的包含列的索引
3)在非主键列上创建相同顺序包含列的索引
CREATEUNIQUEINDEXIX6ONTest_Table(Col4)
4)在不同非主键列创建不同顺序的索引
CREATEINDEXIX8ONTest_Table(Col3,Col2);
这样重复的索引,在执行DML操作(插入、更新、删除)的时候需要更新索引。
3.查找重复索引
一般不会有人特意创建重复索引。有时候,神不知鬼不觉的创建了,有时候是因为创建新的索引是没有检查当前列是否已经存在索引。那么怎么样才能它们暴露来呢?
1)使用SQLServerManagementStudio(SSMS,但是在SQLServer有很多数据库,数据库中又有大量表和索引的情况下,使用SSMS并不是一个快捷的方式。
2)使用sp_helpindex查找重复索引
3)使用SQLServer系统目录,可以在SQLServer数据库上使用和开发脚本查找重复索引,这是一个比较方便并灵活的方式。
阅读导航
1.概述
很多人都知道索引在数据库上的是有利有弊的。像其他主流商业数据库一样SQLServer允许在一个列上重复创建索引。因为SQLServer没有限制创建重复索引的数量,只是限制数据库的一个表上最多可以创建999重复索引,所以这就增加了数据库中存在重复索引的可能性。表的列上存在重复索引的话,可能会明显的损害数据库性能,因为SQLServer必须分别维护每一个重复索引。此外,SQLServer优化查询语句时,查询优化器也会考虑这个问题,这就导致一系列性能问题。要理解什么事实重复索引、怎么样找到它们、怎么样移除它们。
2.什么是重复索引
首先假设有一个表Test_Table有四个列(Col1,Col2,Col3,Col4)
CREATE TABLETest_Table ( Col1 int NOT NULL PRIMARY KEY, Col2varchr(30) NOT NULL, Col3varchr(30) NOT NULL, Col4varchr(30) NOT NULL, )
1)在主键列上创建不同类型的索引
CREATEUNIQUECLUSTEREDINDEXIX1ONTest_Table(Col1);
CREATEINDEXIX2ONTest_Table(Col1);
2)在非主键列上创建不同顺序的包含列的索引
CREATEINDEXIX3ONTest_Table(Col4)
INCLUDE(Col2,Col3);
CREATEINDEXIX4ONTest_Table(Col4)
INCLUDE(Col3,Col2);
3)在非主键列上创建相同顺序包含列的索引
CREATEINDEXIX5ONTest_Table(Col4)
INCLUDE(Col2,Col3);
CREATEUNIQUEINDEXIX6ONTest_Table(Col4)
INCLUDE(Col2,Col3);
4)在不同非主键列创建不同顺序的索引
CREATEINDEXIX7ONTest_Table(Col3,Col2);
CREATEINDEXIX8ONTest_Table(Col3,Col2);
这样重复的索引,在执行DML操作(插入、更新、删除)的时候需要更新索引。
3.查找重复索引
一般不会有人特意创建重复索引。有时候,神不知鬼不觉的创建了,有时候是因为创建新的索引是没有检查当前列是否已经存在索引。那么怎么样才能它们暴露来呢?
1)使用SQLServerManagementStudio(SSMS,但是在SQLServer有很多数据库,数据库中又有大量表和索引的情况下,使用SSMS并不是一个快捷的方式。
2)使用
3)使用SQLServer系统目录,可以在SQLServer数据库上使用和开发脚本查找重复索引,这是一个比较方便并灵活的方式。
SQL系统目录:
a.
b.
c.
d.
下面是包含列对象类型的表:
a)表值程序集函数(FT)
b)内联表值SQL函数(IF)
c)内部表(IT)
d)系统表(S)
e)表值SQL函数(TF)
f)用户表(U)
g)视图(V)
有一种是列出所有索引在哪个表上面,它们被扫描多少次,被更新多少次,在内存中的大小,这些对我们有用的信息
SELECT
sch.name+'.'+t.nameAS[ TableName],
i.nameAS[ IndexName],
i.type_desc,
ISNULL(user_updates,0)AS[TotalWrites],
ISNULL(user_seeks+user_scans+user_lookups,0)AS[TotalReads],
s.last_user_seek,
s.last_user_scan,
s.last_user_lookup,
ISNULL(user_updates,0)-ISNULL((user_seeks+user_scans+user_lookups),0)AS[Difference],
p.reserved_page_count*8.0/1024asSpaceInMB FROMsys.indexes ASi WITH(NOLOCK) LEFT OUTER JOINsys.dm_db_index_usage_stats ASs WITH(NOLOCK) ONs.object_id=i.object_id ANDi.index_id=s.index_id ANDs.database_id=db_id() ANDobjectproperty(s.object_id,'IsUserTable')=1 INNER JOIN sys.tables ASt WITH(NOLOCK) ONi.object_id=t.object_id INNER JOIN sys.schemas ASsch WITH(NOLOCK) ONt.schema_id=sch.schema_id LEFT OUTER JOINsys.dm_db_partition_stats ASp WITH(NOLOCK) ONi.index_id=p.index_id andi.object_id=p.object_id WHERE(1=1)
--ANDISNULL(user_updates,0)>=ISNULL((user_seeks+user_scans+user_lookups),0)--显示包含没有使用的约束在内的所有约束
--ANDISNULL(user_updates,0)-ISNULL((user_seeks+user_scans+user_lookups),0)>0--仅仅显示那些已经使用的索引
--ANDi.index_id>1 --非第一索引
--ANDi.is_primary_key<>1 --不是作为主键被定义的
--ANDi.is_unique_constraint<>1--不是UniqueConstraintsORDER BY[ TableName],[ indexname]
还有一种是基于列查找重复索引
/*执行这个脚本后,索引将会以三个报表的实行展现出来
请看下面:
1.列出所有索引和约束的关键信息
2.列出表潜在的冗余索引
3.列出表潜在的反向索引
*/
--创建一个存放索引信息的表DECLARE@AllIndexes TABLE(
[TableID][ int] NOT NULL,
[Schema][sysname] NOT NULL,
[TableName][sysname] NOT NULL,
[IndexID][ int] NULL,
[IndexName][ nvarchar](128) NULL,
[IndexType][ varchar](12) NOT NULL,
[ConstraintType][ varchar](11) NOT NULL,
[ObjectType][varchar](10) NOT NULL,
[AllColName][nvarchar](2078) NULL,
[ColName1][nvarchar](128) NULL,
[ColName2][nvarchar](128) NULL,
[ColName3][nvarchar](128) NULL,
[ColName4][nvarchar](128) NULL,
[ColName5][nvarchar](128) NULL,
[ColName6][nvarchar](128) NULL,
[ColName7][nvarchar](128) NULL,
[ColName8][nvarchar](128) NULL,
[ColName9][nvarchar](128) NULL,
[ColName10][nvarchar](128) NULL
)
--加载索引信息到下面语句INSERT INTO@AllIndexes
([TableID],[ Schema],[ TableName],[ IndexID],[ IndexName],[ IndexType],[ ConstraintType],[ObjectType]
,[AllColName],[ColName1],[ColName2],[ColName3],[ColName4],[ColName5],[ColName6],[ColName7],[ColName8],
[ColName9],[ColName10])SELECTo.[object_id] AS[ TableID],u.[name] AS[ Schema],o.[name] AS[ TableName],
i.[index_id]AS[ IndexID]
,CASEi.[name] WHENo.[name] THEN'**SameasTableName**' ELSEi.[name] END AS[ IndexName], CASEi.[type] WHEN1 THEN'CLUSTERED' WHEN0 THEN'HEAP' WHEN2 THEN'NONCLUSTERED' WHEN3 THEN'XML' ELSE'UNKNOWN' END AS[ IndexType], CASE WHEN(i.[is_primary_key])=1 THEN'PRIMARYKEY' WHEN(i.[is_unique])=1 THEN'UNIQUE' ELSE'' END AS[ ConstraintType], CASE WHEN(i.[is_unique_constraint])=1 OR(i.[is_primary_key])=1 THEN'CONSTRAINT' WHENi.[type]=0 THEN'HEAP' WHENi.[type]=3 THEN'XMLINDEX' ELSE'INDEX' END AS[ObjectType],
(SELECT COALESCE(c1.[name],'') FROM[sys].[columns] ASc1 INNER JOIN[sys].[index_columns] ASic1 ONc1.[object_id]=ic1.[object_id] ANDc1.[column_id]=ic1.[column_id] ANDic1.[key_ordinal]=1 WHEREic1.[object_id]=i.[object_id] ANDic1.[index_id]=i.[index_id])+ CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],2) IS NULL THEN'' ELSE','+INDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],2) END+ CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],3) IS NULL THEN'' ELSE','+INDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],3) END+ CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],4) IS NULL THEN'' ELSE','+INDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],4) END+ CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],5) IS NULL THEN'' ELSE','+INDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],5) END+ CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],6) IS NULL THEN'' ELSE','+INDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],6) END+ CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],7) IS NULL THEN'' ELSE','+INDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],7) END+ CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],8) IS NULL THEN'' ELSE','+INDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],8) END+ CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],9) IS NULL THEN'' ELSE','+INDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],9) END+ CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],10) IS NULL THEN'' ELSE','+INDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],10) END AS[AllColName],
(SELECT COALESCE(c1.[name],'') FROM[sys].[columns] ASc1 INNER JOIN[sys].[index_columns] ASic1 ONc1.[object_id]=ic1.[object_id] ANDc1.[column_id]=ic1.[column_id] ANDic1.[key_ordinal]=1 WHEREic1.[object_id]=i.[object_id] ANDic1.[index_id]=i.[index_id]) AS[ColName1], CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],2) IS NULL THEN'' ELSEINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],2) END AS[ColName2], CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],3) IS NULL THEN'' ELSEINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],3) END AS[ColName3], CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],4) IS NULL THEN'' ELSEINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],4) END AS[ColName4], CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],5) IS NULL THEN'' ELSEINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],5) END AS[ColName5], CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],6) IS NULL THEN'' ELSEINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],6) END AS[ColName6], CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],7) IS NULL THEN'' ELSEINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],7) END AS[ColName7], CASE WHENINDEX_COL('['+u.[name]+'].['+o.[name]+']',i.[index_id],8) IS NULL