从SQL语句的角度提高数据库的访问性能(二)

2014-11-24 13:18:37 · 作者: · 浏览: 1
上加聚集索引,新增的行都是添加在末尾,这样不容易经常产生页分裂。然而,由于大多数查询都是根据客户编号来查的,因此,将聚集索引加在contactid上才有意义。而contactid对于订单表而言,并非顺序字段。

比如“张三”的“contactid”是001,那么“张三”的订单信息必须都放在这张表的第一个数据页上,如果今天“张三”新下了一个订单,那该订单信息不能放在表的最后一页,而是第一页!如果第一页放满了呢?很抱歉,该表所有数据都要往后移动为这条记录腾地方。

SQL Server的索引和Oracle的索引是不同的,SQL Server的聚集索引实际上是对表按照聚集索引字段的顺序进行了排序,相当于oracle的索引组织表。SQL Server的聚集索引就是表本身的一种组织形式,所以它的效率是非常高的。也正因为此,插入一条记录,它的位置不是随便放的,而是要按照顺序放在该放的数据页,如果那个数据页没有空间了,就引起了页分裂。所以很显然,聚集索引没有建在表的顺序字段上,该表容易发生页分裂。

曾经碰到过一个情况,一位哥们的某张表重建索引后,插入的效率大幅下降了。估计情况大概是这样的。该表的聚集索引可能没有建在表的顺序字段上,该表经常被归档,所以该表的数据是以一种稀疏状态存在的。比如张三下过20张订单,而最近3个月的订单只有5张,归档策略是保留3个月数据,那么张三过去的15张订单已经被归档,留下15个空位,可以在insert发生时重新被利用。在这种情况下由于有空位可以利用,就不会发生页分裂。但是查询性能会比较低,因为查询时必须扫描那些没有数据的空位。

重建聚集索引后情况改变了,因为重建聚集索引就是把表中的数据重新排列一遍,原来的空位没有了,而页的填充率又很高,插入数据经常要发生页分裂,所以性能大幅下降。

对于聚集索引没有建在顺序字段上的表,是否要给与比较低的页填充率?是否要避免重建聚集索引?是一个值得考虑的问题!

使用复合索引提高多个where条件的查询速度

复合索引通常拥有比单一索引更好的选择性。而且,它是特别针对某个where条件所设立的索引,它已经进行了排序,所以查询速度比单索引更快。复合索引的引导字段必须采用“选择性高”的字段。比如有3个字段:日期,性别,年龄。大家看,应该采用哪个字段作引导字段?显然应该采用“日期”作为引导字段。日期是3个字段中选择性最高的字段。

这里有一个例外,如果日期同时也是聚集索引的引导字段,可以不建复合索引,直接走聚集索引,效率也是比较高的。

不要把聚集索引建成“复合索引”,聚集索引越简单越好,选择性越高越好!聚集索引包括2个字段尚可容忍。但是超过2个字段,应该考虑建1个自增字段作为主键,聚集索引可以不做主键。

使用like进行模糊查询时应注意尽量不要使用前%

有的时候会需要进行一些模糊查询比如

Select * from contact where username like ‘%yue%’

关键词%yue%,由于yue前面用到了“%”,因此该查询必然走全表扫描,除非必要,否则不要在关键词前加%,

SQL Server 表连接的三种方式

(1) Merge Join

(2) Nested Loop Join

(3) Hash Join

SQL Server 2000只有一种join方式——Nested Loop Join,如果A结果集较小,那就默认作为外表,A中每条记录都要去B中扫描一遍,实际扫过的行数相当于A结果集行数x B结果集行数。所以如果两个结果集都很大,那Join的结果很糟糕。

SQL Server 2005新增了Merge Join,如果A表和B表的连接字段正好是聚集索引所在字段,那么表的顺序已经排好,只要两边拼上去就行了,这种join的开销相当于A表的结果集行数加上B表的结果集行数,一个是加,一个是乘,可见merge join 的效果要比Nested Loop Join好多了。

如果连接的字段上没有索引,那SQL2000的效率是相当低的,而SQL2005提供了Hash join,相当于临时给A,B表的结果集加上索引,因此SQL2005的效率比SQL2000有很大提高,我认为,这是一个重要的原因。

总结一下,在表连接时要注意以下几点:

(1) 连接字段尽量选择聚集索引所在的字段

(2) 仔细考虑where条件,尽量减小A、B表的结果集

(3) 如果很多join的连接字段都缺少索引,而你还在用SQL2000,干紧升级吧.

Row_number 会导致表扫描,用临时表分页更好

ROW_Number分页的测试结果:

使用ROW_Number来分页:CPU 时间= 317265 毫秒,占用时间= 423090 毫秒

使用临时表来分页:CPU 时间= 1266 毫秒,占用时间= 6705 毫秒

ROW_Number实现是基于order by的,排序对查询的影响显而易见。

其他

诸如有的写法会限制使用索引

Select * from tablename where chgdate +7 < sysdate

Select * from tablename where chgdate < sysdate -7

摘自 tearsmo的专栏