--Ref SQL Server 索引基础知识系列文章SQL Server 索引结构及其使用系列文章 --用法总结 下面的表总结了何时使用聚集索引或非聚集索引(很重要):
动作描述使用聚集索引使用非聚集索引列经常被分组排序应应返回某范围内的数据应不应--物理顺序不同一个或极少不同值不应不应--selectivity小小数目的不同值应不应大数目的不同值不应应频繁更新的列不应应外键列应应主键列应应频繁修改索引列不应应
上边文章里还有些重点 一个堆集在sysindexes内有一行,其indid=0;某个表和视图的聚集索引在sysindexes内有一行,其indid=1,root列指向聚集索引B树的顶端;某个表或视图的非聚集索引在索引在sysindexes内也有一行,其indid值从2到250,root列指向非聚集索引B树的顶端;SQL Server 的数据文件中有一类是IAM,即索引分配映射表,它存储有关表和索引所使用的扩展盘区信息;Bookmark Lookup逻辑运算符和物理运算符使用书签(行 ID 或聚集键)在表或聚集索引内查找相应的行;
--是否值得建索引
无论在哪个数据库里都会有这样的疑问,但是这里永远有三个标准帮助我们来选择,他们是selectivity,density,distribution
selectivity:首先要看需要建索引列的选择性,例如 select * from test where id = 1 -- 假定select count(*) from test 是10000 那么这个的选择性就是 1/10000,选择性很高,适合建立索引 select * from test where id > 1 -- 假定select count(*) from test 是10000 那么这个的选择性就是 9999/10000,选择性很低,不适合建立索引 除非在id字段是聚集索引,如果采用非聚集索引,反而变成需要读至少9999页以上,因为每读取一条记录时都要将整页读出,再从中取出目标记录,就算数据记录在同一页上也要读多次 density:密度指键值唯一的记录条数分之一 select 1 / ( select count ( distinct id) from test) -- 当结果越小也就是唯一性越高,就越合适建立索引,也可以使用以下方法检测看传回的All Density值 Create index idx_id on test(id) DBCC Show_Statistics(test,idx_id) distribution:一个范围之内的记录条数,或者某个分区的记录条数看看是否建多了索引select * from sys.dm_db_index_usage_stats where object_id=object_id('table_name')一些分析索引缺失的视图 (SQL Server 2005 Performance Tuning性能调校(含光盘) P300) select * from sys.dm_db_missing_index_groups select * from sys.dm_db_missing_index_group_stats select * from sys.dm_db_missing_index_details SELECT mig. * , statement AS table_name, column_id, column_name, column_usage FROM sys.dm_db_missing_index_details AS mid CROSS APPLY sys.dm_db_missing_index_columns (mid.index_handle) INNER JOIN sys.dm_db_missing_index_groups AS mig ON mig.index_handle = mid.index_handle ORDER BY mig.index_group_handle, mig.index_handle, column_id; 通过动态管理对象sys.dm_db_missing_index_details和sys.dm_db_missing_index_columns函数返回的结果呈现所需索引键数据行是相等(Equality),不相等(Inequality)或包容(Include) sys.dm_db_missing_index_details视图会在Equality_Columns,Inequality_Columns或Include_Columns等行返回这些信息 sys.dm_db_missing_index_columns函数会在其column_usage数据行中返回此信息 所以最后的规则就是将Equality_Columns放在最前边,Inequality_Columns随后,然后把Include_Columns放到Include子句中 create index idx_test on test(Equality_Columns,Inequality_Columns) include (Include_Columns_1,Include_Columns_2)--一些测试(这个是我看别人文章的总结,忘记出处了,抱歉)
用聚合索引比用一般的主键作order by时,速度快了3/10。事实上,如果数据量很小的话,用聚集索引作为排序列要比使用非聚集索引速度快得明显的多;而数据量如果很大的话,如10万以上,则二者的速度差别不明显。 时间搜索:使用聚合索引内的时间段,搜索时间会按数据占整个数据表的百分比成比例减少,而无论聚合索引使用了多少个 select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi > '' 2004 - 1 - 1 '' --用时:6343毫秒(提取100万条) 整年 select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi > '' 2004 - 6 - 6 '' --用时:3170毫秒(提取50万条) 半年 select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi = '' 2004 - 9 - 16 '' --用时:3326毫秒(和上句的结果一样.如果采集的数量一样,那么用大于号和等于号是一样的,和半年的数据量一样) select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi > '' 2004 - 1 - 1 '' and fariqi < '' 2004 - 6 - 6 '' --用时:3280毫秒 半年 --得出以上速度的方法是:在各个select语句前加: declare @d datetime set @d = getdate () -- SQL Query select [ 语句执行花费时间(毫秒) ] = datediff (ms, @d , getdate ())--碎片
读书笔记 - 高效维护数据库的关键技巧 --统计信息对索引使用的影响 建立测试环境 建立测试环境 USE Tempdb -- 测试统计过期的结果 SET NOCOUNT ON SET STATISTICS IO OFF SET STATISTICS PROFILE OFF CREATE TABLE tblTest(UserId INT IDENTITY ( 1 , 1 ) PRIMARY KEY NONCLUSTERED ,UserName NVARCHAR ( 20 ),Gender NCHAR ( 1 )) -- 一开始构造 100000 笔 '女' 一笔 '男' 的悬殊记录差异 INSERT tblTest VALUES ( ' Hello World ' , ' 男 ' ) DECLARE @int INT SET @int = 1 WHILE @int < 100000 BEGIN INSERT tblTest VALUES ( ' Hello ' + CONVERT ( NVARCHAR , @int ), -- CASE WHEN @int%2 = 0 THEN '男' ELSE '女' END ' 女 ' ) SET @int = @int + 1 END执行计划建立,更新,删除命令 -- 执行计划建立,更新,删除命令 ALTER DATABASE SET CREATE STATISTICS DBCC SHOW_STATISTICSsp_help ' et_order ' DBCC SHOW_STATISTICS ( ' et_order ' , idx_et_0); DROP STATISTICS sp_autostatssp_createstats UPDATE STATISTICS
统计数据的影响 -- 此时建立索引所同时产生的统计会记录如此悬殊的比值 CREATE INDEX idxGender ON tblTest(Gender) EXEC sp_helpindex tblTest -- 没有单独的统计数据 EXEC sp_helpstats tblTest -- 统计是正确的,索引合用于当下的查询 SET STATISTICS IO ON SELECT * FROM tblTest WHERE Gender = ' 男 ' -- 强迫表扫描 SELECT * FROM tblTest WITH ( INDEX ( 0 )) WHERE Gender = ' 男 ' SET STATISTICS IO OFF -- 故意要求不要自动更新统计数据 -- EXEC sp_dboption 'Credit','Auto Update Statistics', { TRUE | FALSE} --针对整个表 EXEC sp_autostats ' tblTest ' , ' OFF ' ,idxGender -- 将记录改成 1:1 UPDATE tblTest SET Gender = ' 男 ' WHERE UserID % 2 = 0 SELECT Gender, COUNT ( * ) FROM tblTest GROUP BY Gender -- 比对一下用错索引时,两者的 I/O 差异 SET STATISTICS IO ON -- 通过 SET STATISTICS PROFILE 输出的 Rows 和 EstimateRows -- 可以比较真实与估计的记录数差异 SET STATISTICS PROFILE ON SELECT * FROM tblTest WHERE Gender = ' 男 ' -- 强迫表扫描 SELECT * FROM tblTest WITH ( INDEX ( 0 )) WHERE Gender = ' 男 ' DBCC SHOW_STATISTICS(tblTest,idxGender) -- 这个是建立在统计信息基础上的,上边把统计信息停止后,这个返回的结果是错误的 -- 做完统计更新后,可以再试一次前述的范例 -- 但要先清除旧的运行计划 UPDATE STATISTICS tblTest DBCC FREEPROCCACHE --
转载于:https://www.cnblogs.com/buro79xxd/archive/2010/03/09/1681903.html
相关资源:各显卡算力对照表!