SQL的优化
优化的方式:
一、SQL语句的优化
1、表尽量使用别名,字段尽量使用别名.字段名,这样子,可以减少oracle数据库解析字段名。而且把不需要的字段名剔除掉,只保留有用的字段名,不要一直使用 select *。
2、关联查询时,选择好主表。oracle解析器对from 后面的表的解析是从右到左的,所以把数据量较小的表作为主表,然后和其他表进行关联,假如存在三个以下表,把同时交叉关联的表作为主表,提高查询效率。
3、where 条件后面的的条件解析是从下向上,从后先前解析执行的,所以可以把过滤数据量较多的条件放在最后面。
4、多利用表中数据行的rowid,rowid代表着表中数据存在的物理地址。例如删除重复记录的时候,可以根据rowid进行删除。
5、减少对表的查询,特别在子查询中,能尽量少重复访问表,就减少。
6、避免使用耗资源的操作,如distinct、Union、minus等这种需要全表查询的操作。
7、优化分组group by ,对group by字段要进行添加锁引,如果分组当中含有查询条件,要改写为where条件进行过滤后,再进行分组,而不是直接进行 having 条件。
8、用EXISTS替代IN、用NOT EXISTS替代 NOT IN,因为 not in是低效的,它必须对该字段的全部数据进行排序。
9、要合理利用索引字段提高查询效率。特别是常用的关联字段可以增加索引,主键、或者某些唯一字段。
10、利用>=替代>,因为>=可以直接定位到=的位置,而大于必须先定位位置,然后再查询下一个数据。耗时不一样。
11、最后一个一定要学会查看执行计划,查看相关查询条件是否进入索引,找出问题所在,定位问题。
二、通过索引优化
索引建立准则:
- 确定针对该表的操作是⼤量的查询操作还是⼤量的增删改操作。
- 尝试建⽴索引来帮助特定的查询。检查⾃⼰的sql语句,为那些频繁在where⼦句中出现的字段建⽴索引。
- where语句中不得不对查询列采⽤函数查询,如upper函数,最好建⽴相应函数索引;
- 在SQL语句中经常进⾏GROUP BY、ORDER BY的字段上建⽴索引
- ⽤于联接的列(主健/外健)上建⽴索引;
- 在经常存取的多个列上建⽴复合索引,但要注意复合索引的建⽴顺序要按照使⽤的频度来确定;
- 尝试建⽴复合索引来进⼀步提⾼系统性能。修改复合索引将消耗更长时间,同时,复合索引也占磁盘空间。
- 对于⼩型的表,建⽴索引可能会影响性能
- 在不同值较少的字段上不必要建⽴索引,如性别字段;
- 应该避免对具有较少值的字段进⾏索引。
- 避免选择⼤型数据类型的列作为索引。
- 缺省情况下建⽴的是⾮簇集索引,但在以下情况下最好考虑簇集索引,如:含有有限数⽬(不是很少)唯⼀的列;进⾏⼤范围的查询;
- 充分的利⽤索引可以减少表扫描I/0的次数,有效的避免对整表的搜索。当然合理的索引要建⽴在对各种查询的分析和预测中
- 避免在有⼤量并发DML运算的表中使⽤Bitmap索引;
- 经常被更新,或者⼀个表虽然很⼤,但是如果多数查询返回结果都超过表中总⾏数的4%,那么⼀般认为也是不宜建⽴索引的。
- 经常查询的记录数⽬少于表中所有记录总数的5%时就应当创建索引
- 存储索引的表空间最好单独设定
- 随着数据的变化,索引的效率会下降,因此应定期重建索
三、通过分区优化
当表中的数据量不断增⼤,查询数据的速度就会变慢,应⽤程序的性能就会下降,这时就应该考虑对表进⾏分区。表进⾏分区后,逻辑上表仍然是⼀张完整的表,只是将表中的数据在物理上存放到多个表空间(物理⽂件上),这样查询数据时,不⾄于每次都扫描整张表。
Oracle中提供了以下⼏种表分区:
⼀、范围分区:这种类型的分区是使⽤列的⼀组值,通常将该列成为分区键。
⼆、列表分区:该分区的特点是某列的值只有⼏个,基于这样的特点我们可以采⽤列表分区。
三、哈希(散列)分区:这类分区是在列值上使⽤散列算法,以确定将⾏放⼊哪个分区中。当列的值没有合适的条件时,建议使⽤散列分区。
四、复合范围列表分区:这种分区是基于范围分区和列表
四、通过优化器hint 优化
Hint的具体⽤法 和优化器相关的hint 1、/*+ ALL_ROWS */ 表明对语句块选择基于开销的优化⽅法,并获得最佳吞吐量,使资源消耗最⼩化. SELECT /*+ ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT'; 2、/*+ FIRST_ROWS(n) */ 表明对语句块选择基于开销的优化⽅法,并获得最佳响应时间,使资源消耗最⼩化. SELECT /*+FIRST_ROWS(20) */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT'; 3、/*+ RULE*/ 表明对语句块选择基于规则的优化⽅法. SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT'; 和访问路径相关的hint 1、/*+ FULL(TABLE)*/ 表明对表选择全局扫描的⽅法. SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='SCOTT'; 2、/*+ INDEX(TABLE INDEX_NAME) */ 表明对表选择索引的扫描⽅法. SELECT /*+INDEX(BSEMPMS SEX_INDEX) */ * FROM BSEMPMS WHERE SEX='M'; 5、/*+ INDEX_ASC(TABLE INDEX_NAME)*/ 表明对表选择索引升序的扫描⽅法. SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ * FROM BSEMPMS WHERE DPT_NO='SCOTT'; 6、/*+ INDEX_COMBINE*/ 为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合⽅式. SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI) */ * FROM BSEMPMS WHERE SAL<5000000 AND HIREDATE 7、/*+ INDEX_JOIN(TABLE INDEX_NAME1 INDEX_NAME2) */ 当谓词中引⽤的列都有索引的时候,可以通过指定采⽤索引关联的⽅式,来访问数据 select /*+ index_join(t t_ind t_bm) */ id from t where id=100 and object_name='EMPLOYEES' 8、/*+ INDEX_DESC(TABLE INDEX_NAME)*/ 表明对表选择索引降序的扫描⽅法. SELECT /*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ * FROM BSEMPMS WHERE DPT_NO='SCOTT'; 9、/*+ INDEX_FFS(TABLE INDEX_NAME) */ 对指定的表执⾏快速全索引扫描,⽽不是全表扫描的办法. SELECT /* + INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305'; 10、/*+ INDEX_SS(T T_IND) */ 从9i开始,oracle引⼊了这种索引访问⽅式。当在⼀个联合索引中,某些谓词条件并不在联合索引的第⼀列时,可以通过Index Skip Scan来 访问索引获得数据。当联合索引第⼀列的唯⼀值个数很少时,使⽤这种⽅式⽐全表扫描效率⾼。
和表的关联相关的hint /*+ leading(table_1,table_2) */ 在多表关联查询中,指定哪个表作为驱动表,即告诉优化器⾸先要访问哪个表上的数据。 select /*+ leading(t,t1) */ t.* from t,t1 where t.id=t1.id; /*+ order */ 让Oracle根据from后⾯表的顺序来选择驱动表,oracle建议使⽤leading,他更为灵活 select /*+ order */ t.* from t,t1 where t.id=t1.id; /*+ use_nl(table_1,table_2) */ 在多表关联查询中,指定使⽤nest loops⽅式进⾏多表关联。 select /*+ use_nl(t,t1) */ t.* from t,t1 where t.id=t1.id; /*+ use_hash(table_1,table_2) */ 在多表关联查询中,指定使⽤hash join⽅式进⾏多表关联。 select /*+ use_hash(t,t1) */ t.* from t,t1 where t.id=t1.id; 在多表关联查询中,指定使⽤hash join⽅式进⾏多表关联,并指定表t为驱动表。 select /*+ use_hash(t,t1) leading(t,t1) */ t.* from t,t1 where t.id=t1.id; /*+ use_merge(table_1,table_2) */ 在多表关联查询中,指定使⽤merge join⽅式进⾏多表关联。 select /*+ use_merge(t,t1) */ t.* from t,t1 where t.id=t1.id; /*+ no_use_nl(table_1,table_2) */ 在多表关联查询中,指定不使⽤nest loops⽅式进⾏多表关联。 select /*+ no_use_nl(t,t1) */ t.* from t,t1 where t.id=t1.id; /*+ no_use_hash(table_1,table_2) */ 在多表关联查询中,指定不使⽤hash join⽅式进⾏多表关联。 select /*+ no_use_hash(t,t1) */ t.* from t,t1 where t.id=t1.id; /*+ no_use_merge(table_1,table_2) */ 在多表关联查询中,指定不使⽤merge join⽅式进⾏多表关联。 select /*+ no_use_merge(t,t1) */ t.* from t,t1 where t.id=t1.id; 其他常⽤的hint /*+ parallel(table_name n) */ 在sql中指定执⾏的并⾏度,这个值将会覆盖⾃⾝的并⾏度 select /*+ parallel(t 4) */ count(*) from t; /*+ no_parallel(table_name) */ 在sql中指定执⾏的不使⽤并⾏ select /*+ no_parallel(t) */ count(*) from t; /*+ append */以直接加载的⽅式将数据加载⼊库 insert into t /*+ append */ select * from t; /*+ dynamic_sampling(table_name n) */ 设置sql执⾏时动态采⽤的级别,这个级别为0~10 select /*+ dynamic_sampling(t 4) */ * from t where id > 1234 /*+ cache(table_name) */ 进⾏全表扫描时将table置于LRU列表的最活跃端,类似于table的cache属性 select /*+ full(employees) cache(employees) */ last_name from employees
详细查看:https://www.csdn.net/tags/MtTaIgysOTI4NzItYmxvZwO0O0OO0O0O.html --MySQL/Oracle数据库优化总结(非常全面)
https://blog.csdn.net/ctypyb2002/article/details/102712900 --oracle 常用的 hints
https://www.cnblogs.com/laiyaling/p/12803873.html?ivk_sa=1024320u --oracle性能优化之索引