为什么添加了索引后,会加快查询速度吗?
1)单列索引
单列索引是基于单个列所建立的索引,比如:
create index 索引名 on 表名(列名)
2)复合索引
复合索引基于两列或是多列的索引,在同一张表上可以有多个索引,但是要求列的组合必须不同,比如:
create index emp_idxl on emp (ename,job);
create index emp_idxl on emp (job,ename);…………
在压力测试时发现,如果原来的查询在0.1秒之内,那么在40个并发时,平均速度是3秒。目标要求是所有的查询必须要在7秒之内。有好几条SQL都是在7秒左右,肯定不能通过压力测试,必须要优化到2秒之内才有希望通过压力测试。
(注:主要数据表的记录数都会超过60W条),所以只能是在项目组内进行SQL优化。
(因为某些原因,案例所使用的SQL都是经过笔者处理过的,已经不是最原始的SQL了。所以不便于贴出详细的执行计划)
1、索引很重要
当查询的记录数小于表记录总数的10%时,索引的效果是非常明显的。
优化前要看执行计划,去掉不必要的全表扫描,找出花费时间的SQL。然后加上适当的索引。
2.注意复合索引失效
create index n1 on ht(code,status,ht) ;
create index n1 on ht(code,status,ht) ;
在ht表上的ht,code,status三列上已经存在复合索引n1
select * from ht ,qt where ht.ht= qt.ht
select * from ht ,qt where ht.ht= qt.ht
发现这个查询需要20秒左右。
查看执行计划时发现,n1这个索引并没有被使用。
于时,使用提示 index
select index h(n1) from ht h , qt q where h.ht = q.ht
select index h(n1) from ht h , qt q where h.ht = q.ht
使用提示后,查询只需要0.01秒了。
为什么n1这个索引没有被使用呢?
原因就是复合索引的问题。
对于复合索引,复合索引的第一列必须出现在WHERE条件中,复合索引才会被使用。
其实按照ORACEL的说法,“复合索引只有索引的所有列都作为查询条件时,索引才会被使用”。看来并非如此。
因为当时系统还没有上线,所以结合实际情况。因为ht列都会出现在查询的WHERE条件中。所以可以重新建立索引,调整索引列的顺序。
create index n1 on ht(hth,code,status)
create index n1 on ht(hth,code,status)
这样,查询只需要0.01秒了。
3.not exists并不是最快的
有一些SQL优化经验的程序员都知道。总是该用not exists来代替not in.好像not exists就应该是最快的了。其实不尽然。
使用not exists时一定是要进行关联子查询。如果是非关联子查询,not exists是没有意义的。
select * from ht a where not exists ( select id from bills where ht = a.ht and bill_type =1)
select * from ht a where not exists ( select id from bills where ht = a.ht and bill_type =1)
因为ht表的数据量非常大。运行执行计划时发现对ht表的开销非常大。同时还发现ht表的索引失效了。
考虑如果用外关联来代替可能会获得一个更好的性能
再次执行执行计划时,发现两个表是通过 hash join outer方式进行访问。
原来的SQL需要20秒,优化后的SQL只需要0.02秒。
4.合理使用提示
有时使用提示,可以使查询效率提升。
h表和q表的记录数都是60w以上。
select h.a ,h.b,q.a,q.b, q.c from q, h where h.a = q.a and h.b = '' and h.c = ''
select h.a ,h.b,q.a,q.b, q.c from q, h where h.a = q.a and h.b = '' and h.c = ''
在h表的a表有索引。
执行计划发现对h表的a列上的索引进行了index fast full scan访问
对q表进行index range scan 和table access by index rowid访问。
然后进行hash join连接
因为h表都非常大,索引也非常大。就算是对索引进行完全访问,开销也很大。
这两个表的连接方式是比较慢的。
因为在h表是有其它的条件限制,可以过滤掉大部分数据,得到一个小的结果集,再与q表进行nested loop访问。这样性能就会有显著的提升。
所以可以加上提示,要求SQL按照指定的顺序访问,并且使用nested loop进行连接。
原来的SQL需要7秒,优化后的SQL只需要0.7秒。
性能提升10倍
总结:
SQL优化是个技术活,也是个体力活。需要耐心,不断的试验。
首先要会看执行计划,迅速的定位性能慢的SQL片段。
其次就是对建立适当的索引,尽量减少全表扫描
再次就是要对SQL进行优化,对优化前和优化后进行对比
最后就是可以使用提示试试
如果不行就需要对环境进行调优化了。如sort_area等。
建议能不建复合索引的就不建复合索引,相比单键索引,复合索引比单键索引难控制的多。主要遵循以下原则:
建立索引常用的规则如下:
1、表的主键、外键必须有索引;
2、数据量超过300的表应该有索引;
3、经常与其他表进行连接的表,在连接字段上应该建立索引;
4、经常出现在Where子句中的字段,特别是大表的字段,应该建立索引;
5、索引应该建在选择性高的字段上;
6、索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;
7、复合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替: A、正确选择复合索引中的主列字段,一般是选择性较好的字段; B、复合索引的几个字段是否经常同时以AND方式出现在Where子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引; C、如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引; D、如果复合索引所包含的字段超过3个,那么仔细考虑其必要性,考虑减少复合的字段; E、如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引;
8、频繁进行数据操作的表,不要建立太多的索引;
9、删除无用的索引,避免对执行计划造成负面影响; 以上是一些普遍的建立索引时的判断依据。一言以蔽之,索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。因为太多的索引与不充分、不正确的索引对性能都毫无益处:在表上建立的每个索引都会增加存储开销,索引对于插入、删除、更新操作也会增加处理上的开销。另外,过多的复合索引,在有单字段索引的情况下,一般都是没有存在价值的;相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负面影响更大