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、最后一个一定要学会查看执行计划,查看相关查询条件是否进入索引,找出问题所在,定位问题。

二、通过索引优化

  索引建立准则:

  1. 确定针对该表的操作是⼤量的查询操作还是⼤量的增删改操作。
  2. 尝试建⽴索引来帮助特定的查询。检查⾃⼰的sql语句,为那些频繁在where⼦句中出现的字段建⽴索引。
  3. where语句中不得不对查询列采⽤函数查询,如upper函数,最好建⽴相应函数索引;
  4. 在SQL语句中经常进⾏GROUP BY、ORDER BY的字段上建⽴索引
  5. ⽤于联接的列(主健/外健)上建⽴索引;
  6. 在经常存取的多个列上建⽴复合索引,但要注意复合索引的建⽴顺序要按照使⽤的频度来确定;
  7. 尝试建⽴复合索引来进⼀步提⾼系统性能。修改复合索引将消耗更长时间,同时,复合索引也占磁盘空间。
  8. 对于⼩型的表,建⽴索引可能会影响性能
  9. 在不同值较少的字段上不必要建⽴索引,如性别字段;
  10. 应该避免对具有较少值的字段进⾏索引。
  11. 避免选择⼤型数据类型的列作为索引。
  12. 缺省情况下建⽴的是⾮簇集索引,但在以下情况下最好考虑簇集索引,如:含有有限数⽬(不是很少)唯⼀的列;进⾏⼤范围的查询;
  13. 充分的利⽤索引可以减少表扫描I/0的次数,有效的避免对整表的搜索。当然合理的索引要建⽴在对各种查询的分析和预测中
  14. 避免在有⼤量并发DML运算的表中使⽤Bitmap索引;
  15. 经常被更新,或者⼀个表虽然很⼤,但是如果多数查询返回结果都超过表中总⾏数的4%,那么⼀般认为也是不宜建⽴索引的。
  16. 经常查询的记录数⽬少于表中所有记录总数的5%时就应当创建索引
  17. 存储索引的表空间最好单独设定
  18. 随着数据的变化,索引的效率会下降,因此应定期重建索

三、通过分区优化

当表中的数据量不断增⼤,查询数据的速度就会变慢,应⽤程序的性能就会下降,这时就应该考虑对表进⾏分区。表进⾏分区后,逻辑上表仍然是⼀张完整的表,只是将表中的数据在物理上存放到多个表空间(物理⽂件上),这样查询数据时,不⾄于每次都扫描整张表。

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性能优化之索引

posted @ 2022-05-07 16:41  潜摩羯  阅读(200)  评论(0编辑  收藏  举报