以文本方式查看主题 - 中文XML论坛 - 专业的XML技术讨论区 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- SQL Server 索引结构及其使用[转帖] (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=50458) |
-- 作者:一分之千 -- 发布时间:7/24/2007 4:32:00 PM -- SQL Server 索引结构及其使用[转帖] SQL Server 索引结构及其使用(一)------ 深入浅出理解索引结构 一、深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录。微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引、簇集索引)和非聚集索引(nonclustered index,也称非聚类索引、非簇集索引)。下面,我们举例来说明一下聚集索引和非聚集索引的区别: 二、何时使用聚集索引或非聚集索引 下面的表总结了何时使用聚集索引或非聚集索引(很重要): 动作描述 使用聚集索引 使用非聚集索引 事实上,我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如:返回某范围内的数据一项。比如您的某个表有一个时间列,恰好您把聚合索引建立在了该列,这时您查询2004年1月1日至2004年10月1日之间的全部数据时,这个速度就将是很快的,因为您的这本字典正文是按日期进行排序的,聚类索引只需要找到要检索的所有数据中的开头和结尾数据即可;而不像非聚集索引,必须先查到目录中查到每一项数据对应的页码,然后再根据页码查到具体内容。 三、结合实际,谈索引使用的误区 理论的目的是应用。虽然我们刚才列出了何时应使用聚集索引或非聚集索引,但在实践中以上规则却很容易被忽视或不能根据实际情况进行综合分析。下面我们将根据在实践中遇到的实际问题来谈一下索引使用的误区,以便于大家掌握索引建立的方法。 1、主键就是聚集索引 (1)仅在主键上建立聚集索引,并且不划分时间段: Select gid,fariqi,neibuyonghu,title from tgongwen (2)在主键上建立聚集索引,在fariq上建立非聚集索引: select gid,fariqi,neibuyonghu,title from Tgongwen (3)将聚合索引建立在日期列(fariqi)上: select gid,fariqi,neibuyonghu,title from Tgongwen 虽然每条语句提取出来的都是25万条数据,各种情况的差异却是巨大的,特别是将聚集索引建立在日期列时的差异。事实上,如果您的数据库真的有1000万容量的话,把主键建立在ID列上,就像以上的第1、2种情况,在网页上的表现就是超时,根本就无法显示。这也是我摒弃ID列作为聚集索引的一个最重要的因素。得出以上速度的方法是:在各个select语句前加: declare @d datetime select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate()) 3、把所有需要提高查询速度的字段都加进聚集索引,以提高查询速度 (1)select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>''2004-5-5'' (2)select gid,fariqi,neibuyonghu,title from Tgongwen (3)select gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu=''办公室'' 从以上试验中,我们可以看到如果仅用聚集索引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询速度是几乎一样的,甚至比用上全部的复合索引列还要略快(在查询结果集数目一样的情况下);而如果仅用复合聚集索引的非起始列作为查询条件的话,这个索引是不起任何作用的。当然,语句1、2的查询速度一样是因为查询的条目数一样,如果复合索引的所有列都用上,而且查询结果少的话,这样就会形成“索引覆盖”,因而性能可以达到最优。同时,请记住:无论您是否经常使用聚合索引的其他列,但其前导列一定要是使用最频繁的列。 四、其他书上没有的索引使用经验总结 1、用聚合索引比用不是聚合索引的主键速度快 select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16'' select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid<=250000 这里,用聚合索引比用不是聚合索引的主键速度快了近1/4。 2、用聚合索引比用一般的主键作order by时速度快,特别是在小数据量情况下 select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by fariqi select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by gid 这里,用聚合索引比用一般的主键作order by时,速度快了3/10。事实上,如果数据量很小的话,用聚集索引作为排序列要比使用非聚集索引速度快得明显的多;而数据量如果很大的话,如10万以上,则二者的速度差别不明显。 3、使用聚合索引内的时间段,搜索时间会按数据占整个数据表的百分比成比例减少,而无论聚合索引使用了多少个: select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>''2004-1-1'' select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>''2004-6-6'' select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16'' select gid,fariqi,neibuyonghu,reader,title from Tgongwen 4、日期列不会因为有分秒的输入而减慢查询速度 select gid,fariqi,neibuyonghu,reader,title from Tgongwen select gid,fariqi,neibuyonghu,reader,title from Tgongwen 五、其他注意事项 “水可载舟,亦可覆舟”,索引也一样。索引有助于提高检索性能,但过多或不当的索引也会导致系统低效。因为用户在表中每加进一个索引,数据库就要做更多的工作。过多的索引甚至会导致索引碎片。 |
-- 作者:一分之千 -- 发布时间:7/24/2007 4:33:00 PM -- SQL Server 索引结构及其使用(二)-----------改善SQL语句
很多人不知道SQL语句在SQL SERVER中是如何执行的,他们担心自己所写的SQL语句会被SQL SERVER误解。比如: select * from table1 where name=''zhangsan'' and tID > 10000 select * from table1 where tID > 10000 and name=''zhangsan'' 列名 操作符 <常数 或 变量> 或 <常数 或 变量> 操作符列名 Name=’张三’ 价格>5000 5000<价格 Name=’张三’ and 价格>5000 1、Like语句是否属于SARG取决于所使用的通配符的类型 如:name like ‘张%’ ,这就属于SARG 而:name like ‘%张’ ,就不属于SARG。 2、or 会引起全表扫描 3、非操作符、函数引起的不满足SARG形式的语句 ABS(价格)<5000 Name like ‘%三’ 有些表达式,如: WHERE 价格*2>5000 SQL SERVER也会认为是SARG,SQL SERVER会将此式转化为: 4、IN 的作用相当与OR 语句: Select * from table1 where tid in (2,3) 和 Select * from table1 where tid=2 or tid=3 5、尽量少用NOT 6、exists 和 in 的执行效率是一样的 (1)select title,price from titles where title_id in (select title_id from sales where qty>30) 表 ''sales''。扫描计数 18,逻辑读 56 次,物理读 0 次,预读 0 次。 (2)select title,price from titles 表 ''sales''。扫描计数 18,逻辑读 56 次,物理读 0 次,预读 0 次。 我们从此可以看到用exists和用in的执行效率是一样的。 7、用函数charindex()和前面加通配符%的LIKE执行效率一样 select gid,title,fariqi,reader from tgongwen select gid,title,fariqi,reader from tgongwen 8、union并不绝对比or的执行效率高 select gid,fariqi,neibuyonghu,reader,title from Tgongwen select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16'' 看来,用union在通常情况下比用or的效率要高的多。 但经过试验,笔者发现如果or两边的查询列是一样的话,那么用union则反倒和用or的执行速度差很多,虽然这里union扫描的是索引,而or扫描的是全表。 select gid,fariqi,neibuyonghu,reader,title from Tgongwen select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16'' 9、字段提取要按照“需多少、提多少”的原则,避免“select *” select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc select top 10000 gid,fariqi,title from tgongwen order by gid desc select top 10000 gid,fariqi from tgongwen order by gid desc 由此看来,我们每少提取一个字段,数据的提取速度就会有相应的提升。提升的速度还要看您舍弃的字段的大小来判断。 10、count(*)不比count(字段)慢 select count(*) from Tgongwen select count(gid) from Tgongwen select count(fariqi) from Tgongwen select count(title) from Tgongwen 从以上可以看出,如果用count(*)和用count(主键)的速度是相当的,而count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总的速度就越慢。我想,如果用count(*), SQL SERVER可能会自动查找最小字段来汇总的。当然,如果您直接写count(主键)将会来的更直接些。 11、order by按聚集索引列排序效率最高 select top 10000 gid,fariqi,reader,title from tgongwen select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc 从以上我们可以看出,不排序的速度以及逻辑读次数都是和“order by 聚集索引列” 的速度是相当的,但这些都比“order by 非聚集索引列”的查询速度是快得多的。 12、高效的TOP select top 10 * from ( |
-- 作者:一分之千 -- 发布时间:7/24/2007 4:33:00 PM -- SQL Server 索引结构及其使用(三)--------实现小数据量和海量数据的通用分页显示存储过程 建立一个 Web 应用,分页浏览功能必不可少。这个问题是数据库处理中十分常见的问题。经典的数据分页方法是:ADO 纪录集分页法,也就是利用ADO自带的分页功能(利用游标)来实现分页。但这种分页方法仅适用于较小数据量的情形,因为游标本身有缺点:游标是存放在内存中,很费内存。游标一建立,就将相关的记录锁住,直到取消游标。游标提供了对特定集合中逐行扫描的手段,一般使用游标来逐行遍历数据,根据取出数据条件的不同进行不同的操作。而对于多表和大表中定义的游标(大的数据集合)循环很容易使程序进入一个漫长的等待甚至死机。 CREATE procedure pagination1 set nocount on begin set nocount off 从publish 表中取出第 n 条到第 m 条的记录: id 为publish 表的关键字 CREATE PROCEDURE pagination2 DECLARE @Str nVARCHAR(4000) SET @Str=''SELECT TOP ''+CAST(@RecsPerPage AS VARCHAR(20))+'' * FROM PRINT @Str EXEC sp_ExecuteSql @Str SELECT TOP 页大小 * SELECT TOP 页大小 * Select top 10 * from table1 where id>200 select top 页大小 * 页码 方案1 方案2 方案3 从上表中,我们可以看出,三种存储过程在执行100页以下的分页命令时,都是可以信任的,速度都很好。但第一种方案在执行分页1000页以上后,速度就降了下来。第二种方案大约是在执行分页1万页以上后速度开始降了下来。而第三种方案却始终没有大的降势,后劲仍然很足。 --获取指定页的数据: CREATE PROCEDURE pagination3 declare @strSQL varchar(5000) -- 主语句 if @doCount != 0 else end if @PageIndex = 1 set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " end set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from [" if @strWhere != '''' end exec (@strSQL) GO 上面的这个存储过程是一个通用的存储过程,其注释已写在其中了。 在大数据量的情况下,特别是在查询最后几页的时候,查询时间一般不会超过9秒;而用其他存储过程,在实践中就会导致超时,所以这个存储过程非常适用于大容量数据库的查询。 笔者希望能够通过对以上存储过程的解析,能给大家带来一定的启示,并给工作带来一定的效率提升,同时希望同行提出更优秀的实时数据分页算法。 |
-- 作者:一分之千 -- 发布时间:7/24/2007 4:34:00 PM -- SQL Server 索引结构及其使用(四)-------------聚集索引的重要性和如何选择聚集索引 在上一节的标题中,笔者写的是:实现小数据量和海量数据的通用分页显示存储过程。这是因为在将本存储过程应用于“办公自动化”系统的实践中时,笔者发现这第三种存储过程在小数据量的情况下,有如下现象: 1、分页速度一般维持在1秒和3秒之间。 2、在查询最后一页时,速度一般为5秒至8秒,哪怕分页总数只有3页或30万页。 虽然在超大容量情况下,这个分页的实现过程是很快的,但在分前几页时,这个1-3秒的速度比起第一种甚至没有经过优化的分页方法速度还要慢,借用户的话说就是“还没有ACCESS数据库速度快”,这个认识足以导致用户放弃使用您开发的系统。 1、以最快的速度缩小查询范围。 2、以最快的速度进行字段排序。 第1条多用在查询优化时,而第2条多用在进行分页时的数据排序。 而聚集索引在每个表内又只能建立一个,这使得聚集索引显得更加的重要。聚集索引的挑选可以说是实现“查询优化”和“高效分页”的最关键因素。 1、您最频繁使用的、用以缩小查询范围的字段上; 2、您最频繁使用的、需要排序的字段上。 结束语 本篇文章汇集了笔者近段在使用数据库方面的心得,是在做“办公自动化”系统时实践经验的积累。希望这篇文章不仅能够给大家的工作带来一定的帮助,也希望能让大家能够体会到分析问题的方法;最重要的是,希望这篇文章能够抛砖引玉,掀起大家的学习和讨论的兴趣,以共同促进,共同为公安科技强警事业和金盾工程做出自己最大的努力。 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
113.281ms |