概述
如何编写性能比较高的SQL查询语句呢?两个方法:创建合理的索引;书写高效的SQL语句
索引的基本原理
索引分为聚集索引和非聚集索引。一个表只能创建一个聚集索引和N个非聚集索引,这句话的由来主要是由于索引的原理决定的。
数据库中的一张表不论你创建不创建索引,或者,不论你创建那种类型的索引,其在硬盘上的存储是一样的,那么,创建索引和不创建索引,或者,创建聚集索引和非聚集索引的区别在什么地方呢?
其区别是表内数据在内存的存在形式。对于没有创建索引的表,其加载到内存里时,就只有数据块;对于有聚集索引的表,其加载到内存时,会形成一棵树,且叶子节点上就是具体的数据;对于非聚集索引的表(没有聚集索引时),其加载内存时,真实数据为一个独立的块,其索引会形成一个索引树,索引数据的叶子节点对应的是真实数据块的rowid;对于既有非聚集索引,又有聚集索引的表,其加载到内存时,会形成两棵树,具体的数据和聚集索引树在一起,非聚集索引独自有一棵树,此时需要注意,其叶子节点中存放的时聚集索引的index,然后,通过聚集索引的index再去,聚集索引树中找到具体的数据。这个就是为什么一个表只能有一个聚集索引,可以有多个非聚集索引的原理。
如何知道我们的SQL查询语句执行时性能的好坏呢?
我们写一个SQL查询语句,怎么样才能知道这个SQL查询语句是好的还是坏的?
一种方法,我们大家都知道,直接在SQL Server的查询器中执行,然后,其执行状态栏会给出我们相应的结果,如:执行时间(秒);另一种方法,通过执行set statistics io on,开启资源消耗信息,执行set statistics time on,开启执行时间,开启这两个功能后,我们再次运行sql语句时,其结果视图旁边的消息视图内,会出现相应的结果;还有一种方式就是使用SQL Server Profiler工具(工具—SQL Server Profiler),帮助我们监听执行的SQL语句的执行情况,这种方式更适用于我们在程序中无法提取SQL语句的情况。
怎样创建合理的索引?
通过上面的方法,我们可以知道我们的SQL语句的好坏,对于坏的SQL,我们要想法设法的进行相应的改变,但是,对于坏的SQL语句,我们在优化的时候,总得要知道其问题出在了哪里吧,不能说我就那么的改了,所以,此时,我们需要了另一个工具,帮助我们分析,即:执行计划视图(查询—显示执行的查询计划),通过执行计划,可知道我们SQL语句在执行查询的时候,使用了还是没有使用索引。在这里介绍3中查询的方式:table scan,index scan,index seek。
table scan就是全表扫描,直接在真实的数据块中进行全部扫描;index scan就是在索引树上进行全扫描,此时如果是聚集索引,就会直接得到相应的数据(叶子上就是具体的数据),如果是非聚集索引,则需要获得叶子上相应的聚集索引键,然后,再根据聚集索引键在聚集索引树中找到相应的真实数据;index scan就是索引树上的搜索,这种方式的实现跟其内部的原理有关,因为这个是树,所以,根据一些算法(二叉等等)可以快速的定位到具体的数据,这个也分为聚集和非聚集,在这里不再赘述。
通过执行计划,我们可以知道,我们的SQL语句在那块没有使用索引,然后,我们可以改SQL语句,也可以创建相应的索引,这里需要知道,并不是使用了索引就一定块,如果你的数据非常的小,如果你创建的索引非常的多,那么,可能会存在这种情况:不如全表索引的块。所以,在优化我们的SQL时,我们尽量往已有的索引上靠拢,实现不行了,那么,根据数据量的多少,我们看看,是否需要再创建相应的索引。
怎么样才能书写高效的SQL查询语句?
上面一块内容我们知道了,我们的SQL语句应该尽可能的向已有的索引靠拢,那么,如果才能使用到已有的索引呢?你可能会说,我们多创建一些索引不就行了嘛,实在不行每个列都是一个索引,这样不就可以使用到了索引了嘛,按照你说的这种情况,我们姑且不考虑其它,就认为SQL语句执行的时候,使用了索引就是快,但是,我想说的是,及时你每个列上都创建上索引,也不见得你写的SQL语句在执行的时候就是使用到了index seek,为什么呢?因为系统在分析你的SQL语句时,无法找到一个合理的index seek的执行计划,那么,怎么样写我们的SQL语句,才可以使系统经过分析后,得到的执行计划里使用到了index seek呢?怎么样写我们的SQL语句才可以得到最优的执行计划呢?
1、查询列的优化
用到表中的那个列就select谁,不要select * ,除非你每个列都使用,因为select * 和select 所有列是一样的
2、where查询条件的优化
不要对条件列进行相应的操作,如:在列上使用函数,列进行数据类型的转换,列上使用参数运算符(filed + 'aaa'),在列上使用不可参数化的条件(like '%a',not……,or……等),这些都会使索引的实现大大折扣,或者直接就丧失
3、其它
不要使用游标,可以使用集合条件查询代码游标;使用exists代替count(*)进行数据存在与否的验证
总结
索引多了不见得好,没有索引不见得不好;索引的有无,是根据具体的数据量来说的;该列是否要建立索引,是根据这个列在查询时作为条件查询的比重;好的SQL语句,不仅要向索引靠拢,也要屏蔽不必要的数据和执行次数。