应该在ORACLE数据库的哪些字段上建⽴索引where
给数据库建索引的规则
博客分类:
Oracle
建⽴索引常⽤的规则如下:
1、表的主键、外键必须有索引;
2、数据量超过300的表应该有索引;
3、经常与其他表进⾏连接的表,在连接字段上应该建⽴索引;
4、经常出现在Where⼦句中的字段,特别是⼤表的字段,应该建⽴索引;
5、索引应该建在选择性⾼的字段上;
6、索引应该建在⼩字段上,对于⼤的⽂本字段甚⾄超长字段,不要建索引;
7、复合索引的建⽴需要进⾏仔细分析;尽量考虑⽤单字段索引代替:
A、正确选择复合索引中的主列字段,⼀般是选择性较好的字段;
B、复合索引的⼏个字段是否经常同时以AND⽅式出现在Where⼦句中?单字段查询是否极少甚⾄没有?如果是,则可以建⽴复合索引;否则考虑单字段索引;
C、如果复合索引中包含的字段经常单独出现在Where⼦句中,则分解为多个单字段索引;
D、如果复合索引所包含的字段超过3个,那么仔细考虑其必要性,考虑减少复合的字段;
E、如果既有单字段索引,⼜有这⼏个字段上的复合索引,⼀般可以删除复合索引;
8、频繁进⾏数据操作的表,不要建⽴太多的索引;
9、删除⽆⽤的索引,避免对执⾏计划造成负⾯影响;
以上是⼀些普遍的建⽴索引时的判断依据。⼀⾔以蔽之,索引的建⽴必须慎重,对每个索引的必要性都应该经过仔细分析,要有建⽴的依据。因为太多的索引与不充分、不正确的索引对性能都毫⽆益处:在表上建⽴的每个索引都会增加存储开销,索引对于插⼊、删除、更新操作也会增加处理上的开销。另外,过多的
复合索引,在有单字段索引的情况下,⼀般都是没有存在价值的;相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负⾯影响更⼤
-------------------------------------------------------------------------------------------------------------------
作者:guojunfeng提交⽇期:2006-9-17 1:07:00
申明:
下⾯内容来⾃
www.doczj/doc/f8a74046a8956bec0975e366.html /keylife/iblog_show.asp?xid=9256
1.合理使⽤索引
索引是数据库中重要的数据结构,它的根本⽬的就是为了提⾼查询效率。现在⼤多数的数据库产品都采⽤IBM最先提出的ISAM索引结构。索引的使⽤要恰到好处,其使⽤原则如下:
●在经常进⾏连接,但是没有指定为外键的列上建⽴索引,⽽不经常连接的字段则由优化器⾃动⽣成索引。
●在频繁进⾏排序或分组(即进⾏group by或order by操作)的列上建⽴索引。
●在条件表达式中经常⽤到的不同值较多的列上建⽴检索,在不同值少的列上不要建⽴索引。⽐如在雇员表的“性别”列上只
有“男”与“⼥”两个不同值,因此就⽆必要建⽴索引。如果建⽴索引不但不会提⾼查询效率,反⽽会严重降低更新速度。
●如果待排序的列有多个,可以在这些列上建⽴复合索引(compound index)。
●使⽤系统⼯具。如Informix数据库有⼀个tbcheck⼯具,可以在可疑的索引上进⾏检查。在⼀些数据库服务器上,索引可能失效或者因为频繁操作⽽使得读取效率降低,如果⼀个使⽤索引的查询不明不⽩地慢下来,可以试着⽤tbcheck⼯具检查索引的完整性,必要时进⾏修复。另外,当数据库表更新⼤量数据后,删除并重建索引可以提⾼查询速度。
(1)在下⾯两条select语句中:
select * from table1 where field1<=10000 and field1>=0;
select * from table1 where field1>=0 and field1<=10000;
如果数据表中的数据field1都>=0,则第⼀条select语句要⽐第⼆条select语句效率⾼的多,因为第⼆条select语句的第⼀个条件耗费了⼤量的系统资源。
第⼀个原则:在where⼦句中应把最具限制性的条件放在最前⾯。
(2)在下⾯的select语句中:
select * from tab where a=… and b=… and c=…;
若有索引index(a,b,c),则where⼦句中字段的顺序应和索引中字段顺序⼀致。
第⼆个原则:where⼦句中字段的顺序应和索引中字段顺序⼀致。
以下假设在field1上有唯⼀索引I1,在field2上有⾮唯⼀索引I2。
(3) select field3,field4 from tb where field1='sdf' 快
select * from tb where field1='sdf' 慢,
oracle建立数据库连接
因为后者在索引扫描后要多⼀步ROWID表访问。
(4) select field3,field4 from tb where field1>='sdf' 快
select field3,field4 from tb where field1>'sdf' 慢
因为前者可以迅速定位索引。
(5) select field3,field4 from tb where field2 like 'R%' 快
select field3,field4 from tb where field2 like '%R' 慢,
因为后者不使⽤索引。
(6) 使⽤函数如:
select field3,field4 from tb where upper(field2)='RMN'不使⽤索引。如果⼀个表有两万条记录,建议不使⽤函数;如果⼀个表有五万条以上记录,严格禁⽌使⽤函数!两万条记录以下没有限制。
(7) 空值不在索引中存储,所以
select field3,field4 from tb where field2 is[not] null不使⽤索引。
(8) 不等式如
select field3,field4 from tb where field2!='TOM'不使⽤索引。
相似地,
select field3,field4 from tb where field2 not in('M','P')不使⽤索引。
(9) 多列索引,只有当查询中索引⾸列被⽤于条件时,索引才能被使⽤。
(10) MAX,MIN等函数,如
Select max(field2) from tb使⽤索引。所以,如果需要对字段取max,min,sum等,应该加索引。
⼀次只使⽤⼀个聚集函数,如:
select“min”=min(field1), “max”=max(field1) from tb
不如:select“min”=(select min(field1) from tb) , “max”=(select max(field1) from tb)
(11) 重复值过多的索引不会被查询优化器使⽤。⽽且因为建了索引,修改该字段值时还要修改索引,所以更新该字段的操作⽐没有索引更慢。
(12) 索引值过⼤(如在⼀个char(40)的字段上建索引),会造成⼤量的I/O 开销(甚⾄会超过表扫描的I/O开销)。因此,尽量使⽤整数索引。 Sp_estspace 可以计算表和索引的开销。
(13) 对于多列索引,order by的顺序必须和索引的字段顺序⼀致。
(14) 在sybase中,如果order by的字段组成⼀个簇索引,那么⽆须做order by。记录的排列顺序是与簇索引⼀致的。
(15) 多表联结(具体查询⽅案需要通过测试得到)
where⼦句中限定条件尽量使⽤相关联的字段,且尽量把相关联的字段放在前⾯。
select a.field1,b.field2 from a,b where a.field3=b.field3
1. field3上没有索引的情况下:
对a作全表扫描,结果排序
对b作全表扫描,结果排序
结果合并。
对于很⼩的表或巨⼤的表⽐较合适。
2. field3上有索引
按照表联结的次序,b为驱动表,a为被驱动表
对b作全表扫描
对a作索引范围扫描
如果匹配,通过a的rowid访问
(16) 避免⼀对多的join。如:
select tb1.field3,tb1.field4,tb2.field2 from tb1,tb2 where
tb1.field2=tb2.field2 and tb1.field2=‘BU1032’ and tb2.field2= ‘aaa’ 不如:
declare @a varchar(80)
select @a=field2 from tb2 where field2=‘aaa’
select tb1.field3,tb1.field4,@a from tb1 where field2= ‘aaa’
(16) ⼦查询
⽤exists/not exists代替in/not in操作
⽐较:
select a.field1 from a where a.field2 in(select b.field1 from b where b.field2=100)
select a.field1 from a where exists( select 1 from b where
a.field2=
b.field1 and b.field2=100)
select field1 from a where field1 not in( select field2 from b) select field1 from a where not exists( select 1 from b where
b.field2=a.field1)
(17) 主、外键主要⽤于数据约束,sybase中创建主键时会⾃动创建索引,外键与索引⽆关,提⾼性能必须再建索引。
(18) char类型的字段不建索引⽐int类型的字段不建索引更糟糕。建索引后性能只稍差⼀点。
(19) 使⽤count(*)⽽不要使⽤count(column_name),避免使⽤
count(distinct column_name)。
(20) 等号右边尽量不要使⽤字段名,如:
select * from tb where field1 = field3
(21) 避免使⽤or条件,因为or不使⽤索引。
2.避免使⽤order by和group by字句。
因为使⽤这两个⼦句会占⽤⼤量的临时空间(tempspace),如果⼀定要使⽤,可⽤视图、⼈⼯⽣成临时表的⽅法来代替。
如果必须使⽤,先检查memory、tempdb的⼤⼩。
测试证明,特别要避免⼀个查询⾥既使⽤join⼜使⽤group by,速度会⾮常慢!
3.尽量少⽤⼦查询,特别是相关⼦查询。因为这样会导致效率下降。
⼀个列的标签同时在主查询和where⼦句中的查询中出现,那么很可能当主查询中的列值改变之后,⼦查询必须重新查询⼀次。查询嵌套层次越多,效率越低,因此应当尽量避免⼦查询。如果⼦查询不可避免,那么要在⼦查询中过滤掉尽可能多的⾏。
4.消除对⼤型表⾏数据的顺序存取
在嵌套查询中,对表的顺序存取对查询效率可能产⽣致命的影响。⽐如采⽤顺序存取策略,⼀个嵌套3层的查询,如果每层都查询1000⾏,那么这个查询就要查询10亿⾏数据。避免这种情况的主要⽅法就是对连接的列进⾏索引。例如,两个表:学⽣表(学号、姓名、年龄……)和选课表(学号、课程号、成绩)。如果两个表要做连接,就要在“学号”这个连接字段上建⽴索引。
还可以使⽤并集来避免顺序存取。尽管在所有的检查列上都有索引,但某些形式的where⼦句强迫优化器使⽤顺序存取。下⾯的查询将强迫对orders表执⾏顺序操作:
SELECT* FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008
虽然在customer_num和order_num上建有索引,但是在上⾯的语句中优化器还是使⽤顺序存取路径扫描整个表。因为这个语句要检索的是分离的⾏的集合,所以应该改为如下语句:
SELECT* FROM orders WHERE customer_num=104 AND order_num>1001 UNION
SELECT* FROM orders WHERE order_num=1008
这样就能利⽤索引路径处理查询。
5.避免困难的正规表达式
MATCHES和LIKE关键字⽀持通配符匹配,技术上叫正规表达式。但这种匹配特别耗费时间。例如:SELECT* FROM customer WHERE zipcode LIKE “98_ _ _”
即使在zipcode字段上建⽴了索引,在这种情况下也还是采⽤顺序扫描的⽅式。如果把语句改为SELECT* FROM customer WHERE zipcode >“98000”,在执⾏查询时就会利⽤索引来查询,显然会⼤⼤提⾼速度。
另外,还要避免⾮开始的⼦串。例如语句:SELECT* FROM customer WHERE zipcode[2,3] >“80”,在where⼦句中采⽤了⾮开始⼦串,因⽽这个语句也不会使⽤索引。
6.使⽤临时表加速查询
把表的⼀个⼦集进⾏排序并创建临时表,有时能加速查询。它有助于避免多重排序操作,⽽且在其他⽅⾯还能简化优化器的⼯作。例如:
SELECT www.doczj/doc/f8a74046a8956bec0975e366.html ,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
AND cust.post code>“98000”
ORDER BY www.doczj/doc/f8a74046a8956bec0975e366.html
如果这个查询要被执⾏多次⽽不⽌⼀次,可以把所有未付款的客户出来放在⼀个临时⽂件中,并按客户的名字进⾏排序:
SELECT www.doczj/doc/f8a74046a8956bec0975e366.html ,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
ORDER BY www.doczj/doc/f8a74046a8956bec0975e366.html
INTO TEMP cust_with_balance
然后以下⾯的⽅式在临时表中查询:
SELECT* FROM cust_with_balance
WHERE postcode>“98000”
临时表中的⾏要⽐主表中的⾏少,⽽且物理顺序就是所要求的顺序,减少了磁盘I/O,所以查询⼯作量可以得到⼤幅减少。
注意:临时表创建后不会反映主表的修改。在主表中数据频繁修改的情况下,注意不要丢失数据。
7.⽤排序来取代⾮顺序存取
⾮顺序磁盘存取是最慢的操作,表现在磁盘存取臂的来回移动。SQL语句隐藏了这⼀情况,使得我们在写应⽤程序时很容易写出要求存取⼤量⾮顺序页的查
有些时候,⽤数据库的排序能⼒来替代⾮顺序的存取能改进查询。
------------------------------------------------------------------------------------------------------------------- ORACLE索引与⾼性能SQL介绍
什么是索引
索引是建⽴在表的⼀列或多个列上的辅助对象,⽬的是加快访问表中的数据;
Oracle存储索引的数据结构是B*树,位图索引也是如此,只不过是叶⼦节点不同B*数索引;
索引由根节点、分⽀节点和叶⼦节点组成,上级索引块包含下级索引块的索引数据,叶节点包含索引数据和确定⾏实际位置的rowid。
使⽤索引的⽬的
加快查询速度
减少I/O操作
消除磁盘排序
何时使⽤索引
查询返回的记录数
排序表<40%
⾮排序表<7%