关于数据库查询优化的那些点

在java项目中,很多时候性能瓶颈卡在数据库交互方面。最近接手一个项目,数据库cpu经常占到100,处理效率慢,sql执行语句的执行分区次数过大。因此,学习总结一下数据库优化的各个点。(oracle)

数据库端优化

一、表分区

作用:

Oracle的表分区功能通过改善可管理性、性能和可用性,从而为各式应用程序带来了极大的好处。通常,分区可以使某些查询以及维护操作的性能大大提高。此外,分区还可以极大简化常见的管理任务,分区是构建千兆字节数据系统或超高可用性系统的关键工具。
分区后的表,在逻辑上还是一个完整的表。在查询方面不需要任何改变。当然,也可以在查询时指定分区。

优点:

1、改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度。

2、增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用;

3、维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可;

4、均衡I/O:可以把不同的分区映射到磁盘以平衡I/O,改善整个系统性能。

缺点:

分区表相关:已经存在的表没有方法可以直接转化为分区表。不过 Oracle 提供了在线重定义表的功能

二、创建索引

优点:

  • 索引是与表相关的一个可选结构——一个表中可以存在索引,也可以不存在索引,不做硬性要求。

  • 用以提高 SQL 语句执行的性能——快速定位我们需要查找的表的内容(物理位置),提高sql语句的执行性能。

  • 减少磁盘I/O——取数据从磁盘上取到数据缓冲区中,再交给用户。磁盘IO非常不利于表的查找速度(效率的提高)

  • 在逻辑上和物理上都独立于表的数据——索引与表完全独立,表里的内容是我们真正感兴趣的内容,而索引则是做了一些编制 ,索引和数据可以存放在不同的表空间下面,可以存放在不同的磁盘下面。

  • Oracle 自动维护索引——当对一个建立索引的表的数据进行增删改的操作时,oracle会自动维护索引,使得其仍然能够更好的工作。

创建索引语法:

create index index_name on table_name (column_name)

应用端优化

一、sql绑定变量

原理

mybatis作为最常用的持久层框架,其底层核心是对jdbc的封装。查询方式本质上还是用statement或者preparedStatement。大家都知道,statement是简单的语句拼接,而preparedStatement是用占位符的方式。preparedStatement可以防止sql注入,而statement不行。
那么,statement和preparedStatement在执行效率方面有什么区别呢?

SQL语句的执行过程分几个步骤:语法检查、分析、执行、返回结果。分析又分为软分析、硬分析。执行sql语句,从共享池查找相同的语句,就叫软分析。硬分析主要是检查该sql所涉及到的所有对象是否有效以及权限等关系,然后根据RBO或CBO模式生成执行计划,然后才执行SQL语句。硬分析的代价很大。

select * from test where a = "yyy"

select * from test where a = "xxx"

当第一次执行第一个sql时,oracle会进行一次硬分析。当执行第二个sql时,oracle并不认为两个sql是相同的,实际只是一个变量不同,但是oralce会再进行一次硬分析,大大的降低了效率,而使用绑定变量,则可以避免这种情况,提升效率。

优点

减少硬分析,提高执行效率

使用

1、jdbc

PreparedStatement preStat = conn.prepareStatement("select * from test where a = ?");
preStat.setString(1,"aaa");
preStat.executeQuery();

2、mybatis

select * from test where a = #{param}

二、sql优化

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0

3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num=10 or num=20 可以这样查询: select id from t where
num=10 union all select id from t where num=20

5.in 和 not in 也要慎用,否则会导致全表扫描,如: select id from t where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了: select id from t where
num between 1 and 3

6.下面的查询也将导致全表扫描: select id from t where name like ‘%abc%’

7.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: select id from t where num/2=100 应改为: select id from t where num=100*2

8.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: select id from t where substring(name,1,3)=‘abc’–name以abc开头的id 应改为: select id
from t where name like ‘abc%’

9.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

10.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

11.不要写一些没有意义的查询,如需要生成一个空表结构: select col1,col2 into #t from t where 1=0 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: create table #t(…)

12.很多时候用 exists 代替 in 是一个好的选择: select num from a where num in(select num from b) 用下面的语句替换: select num from a where
exists(select 1 from b where num=a.num)

13.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

14.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率, 因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。
一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

15.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。 这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

16.尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间, 其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

17.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。 (现在已经无关紧要了,除非只查特定的字段)

你可能感兴趣的:(java,oracle,java,数据库)