一、前言
1.关于Oracle RDBMS执行SQL系统层面10个步骤,具体如下所示,详细见下图所示
1. User访问Oracle Server之前提交一个请求(包含了db_name、instance_name、username、password等信息),Oracle Server接收到请求并通过Password File的验证后,分配SGA内存池,启动后台进程同时创建并启动实例。@b@2. 在启动实例之后User Process与Server Process建立Connect。@b@3. 再通过Server process和Oracle Instance完成建立Sesscion。@b@4. 用户执行SQL语句,由server process接收到并直接与Oracle交互。@b@5. SQL语句通过Server Process到达Oracle Instance,再将SQL载入数据库缓冲区。@b@6. Server Process通知Oracle Database将与SQL语句相关的数据块副本加载到缓冲区中。@b@7. 在数据库缓存区执行SQL语句,并产生”脏缓冲区”。@b@8. 由CKPT检查点进程检查到”脏缓冲区”,并调用DBWn数据库写进程,但在DBWn执行之前,应该由LGWR先将数据文件的原始状态、数据库的改变等信息记录到Redo Log Files。@b@9. 将更新的内容写入到磁盘中的数据文件。@b@10. 返回结果给用户
2.SQL执行顺序
1、from子句组装来自不同数据源的数据;@b@2、where子句基于指定的条件对记录行进行筛选;@b@3、group by子句将数据划分为多个分组;@b@4、使用聚集函数进行计算;@b@5、使用having子句筛选分组;@b@6、计算所有的表达式;@b@7、select 的字段;@b@8、使用order by对结果集进行排序。
(8)SELECT (9) DISTINCT (11) <TOP_specification> <select_list> @b@(1) FROM <left_table> @b@(3) <join_type> JOIN <right_table> @b@(2) ON <join_condition> @b@(4) WHERE <where_condition> @b@(5) GROUP BY <group_by_list> @b@(6) WITH {CUBE | ROLLUP} @b@(7) HAVING <having_condition> @b@(10) ORDER BY <order_by_list>
3.索引优化
oracle的常见有b-tree索引(默认、CREATE INDEX语句时)、位图索引bitmap(字段枚举值)、Hash索引、函数索引(带函数操作)、分区索引、全局索引、反向索引、聚族索引、非聚族索引
1、索引应该经常建在Where子句经常用到的列上,且大表常用字段进行查询,且检索行数在总表行数的5-15%。则应该考虑。@b@2、两表连接的字段,建立索引@b@3、Order By后面常用字段,则也经过进行索引。@b@4、不应该在小表上建设索引。@b@5、where子句中有OR 操作符或单独引用Job 列(索引列的后面列) 则将不会走索引,将会进行全表扫描@b@6、LIKE '%ABC%' 索引失效, 'ABC%' 可以经过索引@b@7、Not Null/Null索引失效@b@8、索引列上不要使用函数,如SELECT column1 FROM tab1 WHERE substr(name,1,3) = 'ABC'@b@9、索引列上不能进行计算SELECT column1 FROM tab1 WHERE column1/10>10 则索引失效,改成SELECT column1 FROM tab1 WHERE column1>10*10 @b@10、索引列上不要使用NOT(!=、 <>)如:SELECT column1 FROM tab1 WHERE column1 ! = 10 改成:SELECT column1 FROM tab1 WHERE column1 > 10 OR column1 < 10 。@b@11、用UNION替换OR@b@12、用EXISTS替代IN、用NOT EXISTS替代NOT IN@b@13、复合索引,必须使用主索引列,如复合索引(deptno,job),则WHERE deptno=20 AND job=’MANAGER’ √、WHERE deptno=20 √、WHERE job=’MANAGER’ AND deptno=20 √、WHERE job=’MANAGER’ ×
4.全表扫描/*+index(a,INEX_CON_CREATE_DATE)index(b,IDX_CD_CON_ID)*/应用示例
select /*+index(a,INEX_CON_CREATE_DATE)index(b,IDX_CD_CON_ID)*/a.cname,@b@ a.ctype,@b@ a.ccode,@b@ b.data_status,@b@ count(1) dcount@b@ from cms_con_detail b@b@ left join cms_content a on b.content_id = a.id@b@ and b.data_status='1'@b@ where a.con_create_date > to_date('2018-01-01', 'yyyy-mm-dd') @b@ group by a.cname,@b@ a.ctype,@b@ a.ccode,@b@ b.data_status@b@ order by a.ccode,a.cname,a.ctype asc
二、示例分析
1.Where后面条件执行筛选顺序从右->左(下面语句第1条执行不报错,第2条会提示除数不能为零)
1.Select 'ok' From Dual Where 1 / 0 = 1 And 1 = 2;@b@2.Select 'ok' From Dual Where 1 = 2 And 1 / 0 = 1;
2.复合索引示例
Create Index i_deptno_job on emp(deptno,job); —>在emp表的deptno、job列建立索引。@b@select * from emp where deptno=66 and job='sals' ->走索引。@b@select * from emp where deptno=66 OR job='sals' ->将进行全表扫描。不走索引@b@select * from emp where deptno=66 ->走索引。@b@select * from emp where job='sals' ->进行全表扫描、不走索引。@b@//如果在where 子句中有OR 操作符或单独引用Job 列(索引列的后面列) 则将不会走索引,将会进行全表扫描。