oracle执行机制
1.客户端发送一条sql给oracle服务器,oracle会看这条sql的执行计划是否存在缓存 如果存在则直接运行,如果不存在执行第二步。
2.如果不存在缓存 则会 进行语法检查(比如我们的sql如果写错了 会报错 就是语法检查这一步做的操作)。然后执行下面的操作(大概是如果你语法没问题。oracle会对你的sql进行优化,并生成执行计划)
3.上面生成的执行计划会保存在缓存中(是为了减少 第二次执行同样的sql时候 再执行硬解析,消耗时间)。
4.oracle最终通过sql执行查询。会在oracle缓存中进行查询如果没有就在oracle硬盘中读取(我们知道oracle数据都是存在硬盘中的,但是每次访问硬盘大量的io操作肯定不可取,所以会读取在缓存中进行查询 缓存中没有 然后再硬盘中读取出来保存在缓存中)。
通过上面 需要注意的 sql语句大小写规范要一致。不然比如第一条sql select * from user 执行了硬解析并保存到了缓存 第二条sql SELECT * FROM USER 会在缓存中查不到 会重新进行硬解析
ps:以前看过sqlserver的执行流程 其实大概也是这样的
避免全表扫描提示查询效率
1、对于null值的查询会进行全表扫描的。所以我们在设计数据的时候对于可能出现null值的字段定义一个默认值 比如"-1" 或者一个‘’ 那么当你要查询学生名为空的所有学生的时候:select * from table t.student.Name =‘-1‘
2、避免隐式转换 比如你在设计数据库的时候 UserId 设置的类型为number 你在客户端进查询的时候select * from user u where u.userid=‘1‘ 这种时候数据库和客户端传递的类型不一致 导致索引失效
3、避免查询条件使用函数 select * from user u where u.createTime=to_date(2017-01-02,‘yyyy-mm-dd‘) 这样也会导致索引失效 全表扫描
4、用exists 替换 in 因为in也会导致索引失效 比如查询班级为一年级的学生 select * from student where s.calssid in(select classid from class where calssName=‘一年级‘)
替换成 select * from student s where exists(select classid from class where className=‘一年级‘ and s.classsid=s.classid)
当然这个举例有点极端
5、用union all 替换or
比如你需要查询年龄为13 岁 或者 15岁 或者17岁的所有学生信息
select * from student s where s.age in(13,15,17) 、
替换成
select * from student s where s.age=13
union all
select * from student s where s.age=15
unoin all
select * from student s where s.age=17
6.模糊查询 ‘%条件%‘ 是全部扫描的 如果业务支持可以改成 ‘条件%‘ 是走索引的
7.join表不能超过3张(表与表之间的关联字段都建立索引) 如果业务支持 可以将数据查询到程序 程序再去取关联数据
List<Student> students=dbhelper.query(select * from student where rownum<=10);
student.ForEach(function(c){
c.studentName=dbhelper.query(select * from class where classid=‘"+c.classId+‘).className
})
ps:这里可能会觉得增加了数据库的负荷。因为取关联数据会给数据库发起10次请求 (其实这10次请求是非常快的 第一是数据库连接池 第二是 上面sql执行机制是直接运行的不会执行硬解析 因为这10条sql是一致的)
8、避免使用select * *会导致oracle解析这个*表里面含有哪些列 而不是直接取。 * 会导致数据传输量 最好需要什么拿什么
总结:上面的优化操作 可能数据量小的时候感觉不到什么 但是上千万数据的时候 往往不规避以上的上的sql会查询很久 而规避了的sql只需要零点几秒