No SQL,No cost. SQL语句是造成数据库开销最大的部分。而不良SQL写法直接导致数据库系统性能下降的情形比比皆是。那么如何才能称得
上高效的SQL语句呢?一是查询优化器为当前的SQL语句生成最佳的执行计划,保证数据读写使用最佳路径;二是设置合理的物理存储结构,如表
的类型,字段的顺序,字段的数据类型等。本文主要描述如何编写高效的SQL语句并给出示例。下面的描述主要分为三个部分,一是编写高效SQL
语句,二是使用索引提高查询性能的部分,三是总结部分。
一、编写高效SQL语句
- 1) 选择最有效的表名顺序(仅适用于RBO模式)
- ORACLE的解析器总是按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中最后的一个表将作为驱动表被优先处理。当FROM子句
- 存在多个表的时候,应当考虑将表上记录最少的那个表置于FROM的最右端作为基表。Oracle会首先扫描基表(FROM子句中最后的那个表)并对
- 记录进行排序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并。如
- 果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引用的表。
-
- 下面的例子使用最常见的scott或hr模式下的表进行演示
-
- 表 EMP 有14条记录
- 表 DEPT 有4条记录
- SELECT /*+ rule */ COUNT( * ) FROM emp, dept;
-
- scott@CNMMBO> set autotrace traceonly stat;
- scott@CNMMBO> SELECT /*+ rule */ COUNT( * ) FROM emp, dept;
-
- Elapsed: 00:00:00.14
-
- Statistics
-
- 1 recursive calls
- 0 db block gets
- 35 consistent gets
- 0 physical reads
- 0 redo size
- 515 bytes sent via SQL*Net to client
- 492 bytes received via SQL*Net from client
- 2 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 1 rows processed
-
- SELECT /*+ rule */ COUNT( * ) FROM dept, emp;
- scott@CNMMBO> SELECT /*+ rule */ COUNT( * ) FROM dept, emp;
-
- Elapsed: 00:00:00.02
-
- Statistics
-
- 1 recursive calls
- 0 db block gets
- 105 consistent gets
- 0 physical reads
- 0 redo size
- 515 bytes sent via SQL*Net to client
- 492 bytes received via SQL*Net from client
- 2 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 1 rows processed
-
- 2) select 查询中避免使用'*'
- 当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 '*' 是一个方便的方法.不幸的是,这是一个非常低效的方法.实际
- 上,ORACLE在解析的过程中, 会将 '*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。
- 注:本文中的例子出于简化演示而使用了select * ,生产环境应避免使用.
-
- 3) 减少访问数据库的次数
- 每当执行一条SQL语句,Oracle 需要完成大量的内部操作,象解析SQL语句,估算索引的利用率,绑定变量, 读数据块等等.由此可
- 见,减少访问数据库的次数,实际上是降低了数据库系统开销
-
-
-
- select ename,job,sal from emp where empno=7788;
-
- select ename,job,sal from emp where empno=7902;
-
-
-
- DECLARE
- CURSOR C1(E_NO NUMBER) IS
- SELECT ename, job, sal
- FROM emp
- WHERE empno = E_NO;
- BEGIN
- OPEN C1 (7788);
- FETCH C1 INTO …, …, …;
- ..
- OPEN C1 (7902);
- FETCH C1 INTO …, …, …;
- CLOSE C1;
- END;
-
-
- SELECT a.ename
- , a.job
- , a.sal
- , b.ename
- , b.job
- , b.sal
- FROM emp a, emp b
- WHERE a.empno = 7788 AND b.empno = 7902;
-
- 注意:在SQL*Plus,SQL*Forms和Pro*C中重新设置ARRAYSIZE参数,可以增加每次数据库访问的检索数据量,建议值为200.
-
- 4) 使用DECODE函数来减少处理时间
-
- select count(*),sum(sal) from emp where deptno=20 and ename like 'SMITH%';
-
- select count(*),sum(sal) from emp where deptno=30 and ename like 'SMITH%';
-
-
- SELECT COUNT( DECODE( deptno, 20, 'x', NULL ) ) d20_count
- , COUNT( DECODE( deptno, 30, 'x', NULL ) ) d30_count
- , SUM( DECODE( deptno, 20, sal, NULL ) ) d20_sal
- , SUM( DECODE( deptno, 30, sal, NULL ) ) d30_sal
- FROM emp
- WHERE ename LIKE 'SMITH%';
-
- 类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中。
-
- 5) 整合简单,无关联的数据库访问
-
-
- SELECT name
- FROM emp
- WHERE empno = 1234;
-
- SELECT name
- FROM dept
- WHERE deptno = 10;
-
- SELECT name
- FROM cat
- WHERE cat_type = 'RD';
-
-
- SELECT e.name, d.name, c.name
- FROM cat c
- , dpt d
- , emp e
- , dual x
- WHERE NVL( 'X', x.dummy ) = NVL( 'X', e.ROWID(+) )
- AND NVL( 'X', x.dummy ) = NVL( 'X', d.ROWID(+) )
- AND NVL( 'X', x.dummy ) = NVL( 'X', c.ROWID(+) )
- AND e.emp_no(+) = 1234
- AND d.dept_no(+) = 10
- AND c.cat_type(+) = 'RD';
-
-
-
- 6) 删除重复记录
-
- DELETE FROM emp e
- WHERE e.ROWID > (SELECT MIN( x.ROWID )
- FROM emp x
- WHERE x.empno = e.empno);
-
- 7) 使用truncate 代替 delete
-
-
-
-
- 8) 尽量多使用COMMIT(COMMIT应确保事务的完整性)
-
-
-
-
-
-
-
- 9) 计算记录条数
-
-
-
- 10) 用Where子句替换HAVING子句
-
-
-
-
- SELECT deptno, AVG( sal )
- FROM emp
- GROUP BY deptno
- HAVING deptno = 20;
-
- scott@CNMMBO> SELECT deptno, AVG( sal )
- 2 FROM emp
- 3 GROUP BY deptno
- 4 HAVING deptno= 20;
-
- Statistics
-
- 0 recursive calls
- 0 db block gets
- 7 consistent gets
- 0 physical reads
- 0 redo size
- 583 bytes sent via SQL*Net to client
- 492 bytes received via SQL*Net from client
- 2 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 1 rows processed
-
- SELECT deptno, AVG( sal )
- FROM emp
- WHERE deptno = 20
- GROUP BY deptno;
-
- scott@CNMMBO> SELECT deptno, AVG( sal )
- 2 FROM emp
- 3 WHERE deptno = 20
- 4 GROUP BY deptno;
-
- Statistics
-
- 0 recursive calls
- 0 db block gets
- 2 consistent gets
- 0 physical reads
- 0 redo size
- 583 bytes sent via SQL*Net to client
- 492 bytes received via SQL*Net from client
- 2 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 1 rows processed
-
- 11) 最小化表查询次数
-
-
- SELECT *
- FROM employees
- WHERE department_id = (SELECT department_id
- FROM departments
- WHERE department_name = 'Marketing')
- AND manager_id = (SELECT manager_id
- FROM departments
- WHERE department_name = 'Marketing');
-
- SELECT *
- FROM employees
- WHERE ( department_id, manager_id ) = (SELECT department_id, manager_id
- FROM departments
- WHERE department_name = 'Marketing')
-
-
-
- UPDATE employees
- SET job_id = ( SELECT MAX( job_id ) FROM jobs ), salary = ( SELECT AVG( min_salary ) FROM jobs )
- WHERE department_id = 10;
-
-
- UPDATE employees
- SET ( job_id, salary ) = ( SELECT MAX( job_id ), AVG( min_salary ) FROM jobs )
- WHERE department_id = 10;
-
- 12) 使用表别名
-
-
- 13) 用EXISTS替代IN
- 在一些基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下,使用EXISTS(或NOT EXISTS)通常
- 将提高查询的效率.
-
- SELECT *
- FROM emp
- WHERE sal > 1000
- AND deptno IN (SELECT deptno
- FROM dept
- WHERE loc = 'DALLAS')
-
-
- SELECT *
- FROM emp
- WHERE empno > 1000
- AND EXISTS
- (SELECT 1
- FROM dept
- WHERE deptno = emp.deptno AND loc = 'DALLAS')
-
- 14) 用NOT EXISTS替代NOT IN
- 在子查询中,NOT IN子句引起一个内部的排序与合并.因此,无论何时NOT IN子句都是最低效的,因为它对子查询中的表执行了一个全表
- 遍历.为避免该情形,应当将其改写成外部连接(OUTTER JOIN)或适用NOT EXISTS
-
- SELECT *
- FROM emp
- WHERE deptno NOT IN (SELECT deptno
- FROM dept
- WHERE loc = 'DALLAS');
-
-
- SELECT e.*
- FROM emp e
- WHERE NOT EXISTS
- (SELECT 1
- FROM dept
- WHERE deptno = e.deptno AND loc = 'DALLAS');
-
-
- SELECT e.*
- FROM emp e LEFT JOIN dept d ON e.deptno = d.deptno
- WHERE d.loc <> 'DALLAS'
-
- 15) 使用表连接替换EXISTS
- 一般情况下,使用表连接比EXISTS更高效
-
- SELECT *
- FROM employees e
- WHERE EXISTS
- (SELECT 1
- FROM departments
- WHERE department_id = e.department_id AND department_name = 'IT');
-
-
- SELECT *
- FROM employees e INNER JOIN departments d ON d.department_id = e.department_id
- WHERE d.department_name = 'IT';
-
- 16) 用EXISTS替换DISTINCT
- 对于一对多关系表信息查询时(如部门表和雇员表),应避免在select 子句中使用distinct,而使用exists来替换
-
-
- SELECT DISTINCT e.department_id, department_name
- FROM departments d INNER JOIN employees e ON d.department_id = e.department_id;
-
-
- SELECT d.department_id,department_name
- from departments d
- WHERE EXISTS
- (SELECT 1
- FROM employees e
- WHERE d.department_id=e.department_id);
-
- EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果
-
-
- 17) 使用 UNION ALL 替换 UNION(如果有可能的话)
- 当SQL语句需要UNION两个查询结果集时,这两个结果集合会以UNION-ALL的方式被合并, 然后在输出最终结果前进行排序。
- 如果用UNION ALL替代UNION, 这样排序就不是必要了。 效率就会因此得到提高。
-
- 注意:
- UNION ALL会输出所有的结果集,而UNION则过滤掉重复记录并对其进行排序.因此在使用时应考虑业务逻辑是否允许当前的结果集存在重复现象
-
- 寻找低效的SQL语句
-
- SELECT executions
- , disk_reads
- , buffer_gets
- , ROUND( ( buffer_gets
- - disk_reads )
- / buffer_gets, 2 )
- hit_ratio
- , ROUND( disk_reads / executions, 2 ) reads_per_run
- , sql_text
- FROM v$sqlarea
- WHERE executions > 0
- AND buffer_gets > 0
- AND ( buffer_gets
- - disk_reads )
- / buffer_gets < 0.80
- ORDER BY 4 DESC;
-
- 18) 尽可能避免使用函数,函数会导致更多的 recursive calls
二、合理使用索引以提高性能
索引依赖于表而存在,是真实表的一个缩影,类似于一本书的目录,通过目录以更快获得所需的结果。Oracle使用了一个复杂的自平衡
B数据结构。即任意记录的DML操作将打破索引的平衡,而定期重构索引使得索引重新获得平衡。通常,通过索引查找数据比全表扫描更高效。
任意的DQL或DML操作,SQL优化引擎优先使用索引来计算当前操作的成本以生成最佳的执行计划。一旦使用索引操出参数optimizer_index_cost_adj
设定的值才使用全表扫描。同样对于多表连接使用索引也可以提高效率。同时索引也提供主键(primary key)的唯一性验证。
除了那些LONG或LONG RAW数据类型,你可以索引几乎所有的列.通常,在大型表中使用索引特别有效.当然,你也会发现,在扫描小表时,使用索
引同样能提高效率。
虽然使用索引能得到查询效率的提高,但是索引需要空间来存储,需要定期维护.尤其是在有大量DML操作的表上,任意的DML操作都将引起索
引的变更这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,
那些不必要的索引反而会使查询反应时间变慢。
DML操作使用索引上存在碎片而失去高度均衡,因此定期的重构索引是有必要的.
- 1) 避免基于索引列的计算
- where 子句中的谓词上存在索引,而此时基于该列的计算将使得索引失效
-
-
- SELECT employee_id, first_name
- FROM employees
- WHERE employee_id + 10 > 150;
-
-
- SELECT employee_id, first_name
- FROM employees
- WHERE employee_id > 160;
-
- 例外情形
- 上述规则不适用于SQL中的MIN和MAX函数
- hr@CNMMBO> SELECT MAX( employee_id ) max_id
- 2 FROM employees
- 3 WHERE employee_id
- 4 + 10 > 150;
-
- 1 row selected.
-
- Execution Plan
-
- Plan hash value: 1481384439
-
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
- | 0 | SELECT STATEMENT | | 1 | 4 | 1 (0)| 00:00:01 |
- | 1 | SORT AGGREGATE | | 1 | 4 | | |
- | 2 | FIRST ROW | | 5 | 20 | 1 (0)| 00:00:01 |
- |* 3 | INDEX FULL SCAN (MIN/MAX)| EMP_EMP_ID_PK | 5 | 20 | 1 (0)| 00:00:01 |
-
-
- 2) 避免在索引列上使用NOT运算或不等于运算(<>,!=)
- 通常,我们要避免在索引列上使用NOT或<>,两者会产生在和在索引列上使用函数相同的影响。 当ORACLE遇到NOT或不等运算时,他就会停止
- 使用索引转而执行全表扫描。
-
-
- SELECT *
- FROM emp
- WHERE NOT ( deptno = 20 );
-
-
- SELECT *
- FROM emp
- WHERE deptno > 20 OR deptno < 20;
-
-
- 需要注意的是,在某些时候, ORACLE优化器会自动将NOT转化成相对应的关系操作符
- 其次如果是下列运算符进行NOT运算,依然有可能选择走索引, 仅仅除了NOT = 之外,因为 NOT = 等价于 <>
-
- “NOT >” to <=
- “NOT >=” to <
- “NOT <” to >=
- “NOT <=” to >
-
- 来看一个实际的例子
- hr@CNMMBO> SELECT *
- 2 FROM employees
- 3 where not employee_id<100;
-
- 107 rows selected.
-
- Execution Plan
-
- Plan hash value: 1445457117
-
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
- | 0 | SELECT STATEMENT | | 107 | 7276 | 3 (0)| 00:00:01 |
- |* 1 | TABLE ACCESS FULL| EMPLOYEES | 107 | 7276 | 3 (0)| 00:00:01 |
-
- Predicate Information (identified by operation id):
-
-
- 1 - filter("EMPLOYEE_ID">=100)
-
- hr@CNMMBO> SELECT *
- 2 FROM employees
- 3 where not employee_id<140;
-
- 67 rows selected.
-
- Execution Plan
-
- Plan hash value: 603312277
-
-
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
- | 0 | SELECT STATEMENT | | 68 | 4624 | 3 (0)| 00:00:01 |
- | 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 68 | 4624 | 3 (0)| 00:00:01 |
- |* 2 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 68 | | 1 (0)| 00:00:01 |
-
- Predicate Information (identified by operation id):
-
- 2 - access("EMPLOYEE_ID">=140)
-
- 3) 用UNION 替换OR(适用于索引列)
- 通常情况下,使用UNION 替换WHERE子句中的OR将会起到较好的效果.基于索引列使用OR使得优化器倾向于使用全表扫描,而不是扫描索引.
- 注意,以上规则仅适用于多个索引列有效。 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低。
-
- SELECT deptno, dname
- FROM dept
- WHERE loc = 'DALLAS' OR deptno = 20;
-
-
- SELECT deptno, dname
- FROM dept
- WHERE loc = 'DALLAS'
- UNION
- SELECT deptno, dname
- FROM dept
- WHERE deptno = 30
-
-
-
- scott@CNMMBO> create table t6 as select object_id,owner,object_name from dba_objects where owner='SYS' and rownum<1001;
-
- scott@CNMMBO> insert into t6 select object_id,owner,object_name from dba_objects where owner='SCOTT' and rownum<6;
-
- scott@CNMMBO> create index i_t6_object_id on t6(object_id);
-
- scott@CNMMBO> create index i_t6_owner on t6(owner);
-
- scott@CNMMBO> insert into t6 select object_id,owner,object_name from dba_objects where owner='SYSTEM' and rownum<=300;
-
- scott@CNMMBO> commit;
-
- scott@CNMMBO> exec dbms_stats.gather_table_stats('SCOTT','T6',cascade=>true);
-
- scott@CNMMBO> select owner,count(*) from t6 group by owner;
-
- OWNER COUNT(*)
-
- SCOTT 5
- SYSTEM 300
- SYS 1000
-
- scott@CNMMBO> select * from t6 where owner='SCOTT' and rownum<2;
-
- OBJECT_ID OWNER OBJECT_NAME
-
- 69450 SCOTT T_TEST
-
- scott@CNMMBO> select * from t6 where object_id=69450 or owner='SYSTEM';
-
- 301 rows selected.
-
- Execution Plan
-
- Plan hash value: 238853296
-
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
- | 0 | SELECT STATEMENT | | 300 | 7200 | 5 (0)| 00:00:01 |
- | 1 | CONCATENATION | | | | | |
- | 2 | TABLE ACCESS BY INDEX ROWID| T6 | 1 | 24 | 2 (0)| 00:00:01 |
- |* 3 | INDEX RANGE SCAN | I_T6_OBJECT_ID | 1 | | 1 (0)| 00:00:01 |
- |* 4 | TABLE ACCESS BY INDEX ROWID| T6 | 299 | 7176 | 3 (0)| 00:00:01 |
- |* 5 | INDEX RANGE SCAN | I_T6_OWNER | 300 | | 1 (0)| 00:00:01 |
-
-
- Predicate Information (identified by operation id):
-
- 3 - access("OBJECT_ID"=69450)
- 4 - filter(LNNVL("OBJECT_ID"=69450))
- 5 - access("OWNER"='SYSTEM')
-
- Statistics
-
- 0 recursive calls
- 0 db block gets
- 46 consistent gets
- 0 physical reads
- 0 redo size
- 11383 bytes sent via SQL*Net to client
- 712 bytes received via SQL*Net from client
- 22 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 301 rows processed
-
- scott@CNMMBO> select * from t6 where owner='SYSTEM' or object_id=69450;
-
- 301 rows selected.
-
- Execution Plan
-
- Plan hash value: 238853296
-
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
- | 0 | SELECT STATEMENT | | 300 | 7200 | 5 (0)| 00:00:01 |
- | 1 | CONCATENATION | | | | | |
- | 2 | TABLE ACCESS BY INDEX ROWID| T6 | 1 | 24 | 2 (0)| 00:00:01 |
- |* 3 | INDEX RANGE SCAN | I_T6_OBJECT_ID | 1 | | 1 (0)| 00:00:01 |
- |* 4 | TABLE ACCESS BY INDEX ROWID| T6 | 299 | 7176 | 3 (0)| 00:00:01 |
- |* 5 | INDEX RANGE SCAN | I_T6_OWNER | 300 | | 1 (0)| 00:00:01 |
-
-
- Predicate Information (identified by operation id):
-
- 3 - access("OBJECT_ID"=69450)
- 4 - filter(LNNVL("OBJECT_ID"=69450))
- 5 - access("OWNER"='SYSTEM')
-
- Statistics
-
- 1 recursive calls
- 0 db block gets
- 46 consistent gets
- 0 physical reads
- 0 redo size
- 11383 bytes sent via SQL*Net to client
- 712 bytes received via SQL*Net from client
- 22 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 301 rows processed
-
- scott@CNMMBO> select * from t6
- 2 where object_id=69450
- 3 union
- 4 select * from t6
- 5 where owner='SYSTEM';
-
- 301 rows selected.
-
- Execution Plan
-
- Plan hash value: 370530636
-
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
- | 0 | SELECT STATEMENT | | 301 | 7224 | 7 (72)| 00:00:01 |
- | 1 | SORT UNIQUE | | 301 | 7224 | 7 (72)| 00:00:01 |
- | 2 | UNION-ALL | | | | | |
- | 3 | TABLE ACCESS BY INDEX ROWID| T6 | 1 | 24 | 2 (0)| 00:00:01 |
- |* 4 | INDEX RANGE SCAN | I_T6_OBJECT_ID | 1 | | 1 (0)| 00:00:01 |
- | 5 | TABLE ACCESS BY INDEX ROWID| T6 | 300 | 7200 | 3 (0)| 00:00:01 |
- |* 6 | INDEX RANGE SCAN | I_T6_OWNER | 300 | | 1 (0)| 00:00:01 |
-
-
- Predicate Information (identified by operation id):
-
- 4 - access("OBJECT_ID"=69450)
- 6 - access("OWNER"='SYSTEM')
-
- Statistics
-
- 1 recursive calls
- 0 db block gets
- 7 consistent gets
- 0 physical reads
- 0 redo size
- 11383 bytes sent via SQL*Net to client
- 712 bytes received via SQL*Net from client
- 22 SQL*Net roundtrips to/from client
- 1 sorts (memory)
- 0 sorts (disk)
- 301 rows processed
-
-
-
-
- 4) 避免索引列上使用函数
-
-
- SELECT acc_num
- , curr_cd
- , DECODE( '20110728'
- , ( SELECT TO_CHAR( LAST_DAY( TO_DATE( '20110728', 'YYYYMMDD' ) ), 'YYYYMMDD' ) FROM dual ), 0
- , adj_credit_int_lv1_amt
- + adj_credit_int_lv2_amt
- - adj_debit_int_lv1_amt
- - adj_debit_int_lv2_amt )
- AS interest
- FROM acc_pos_int_tbl
- WHERE SUBSTR( business_date, 1, 6 ) = SUBSTR( '20110728', 1, 6 ) AND business_date <= '20110728';
-
-
- SELECT acc_num
- , curr_cd
- , DECODE( '20110728'
- , ( SELECT TO_CHAR( LAST_DAY( TO_DATE( '20110728', 'YYYYMMDD' ) ), 'YYYYMMDD' ) FROM dual ), 0
- , adj_credit_int_lv1_amt
- + adj_credit_int_lv2_amt
- - adj_debit_int_lv1_amt
- - adj_debit_int_lv2_amt )
- AS interest
- FROM acc_pos_int_tbl acc_pos_int_tbl
- WHERE business_date >= TO_CHAR( LAST_DAY( ADD_MONTHS( TO_DATE( '20110728', 'yyyymmdd' ), -1 ) )
- + 1, 'yyyymmdd' )
- AND business_date <= '20110728';
-
-
-
- SELECT account_name, amount
- FROM transaction
- WHERE account_name
- || account_type = 'AMEXA';
-
-
- SELECT account_name, amount
- FROM transaction
- WHERE account_name = 'AMEX' AND account_type = 'A';
-
- 5) 比较不匹配的数据类型
-
-
- SELECT *
- FROM acc_pos_int_tbl
- WHERE business_date = 20090201;
-
- Execution Plan
-
- Plan hash value: 2335235465
-
-
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
- | 0 | SELECT STATEMENT | | 37516 | 2857K| 106K (1)| 00:21:17 |
- |* 1 | TABLE ACCESS FULL| ACC_POS_INT_TBL | 37516 | 2857K| 106K (1)| 00:21:17 |
-
-
- Predicate Information (identified by operation id):
-
- 1 - filter(TO_NUMBER("BUSINESS_DATE")=20090201)
-
-
- SELECT *
- FROM acc_pos_int_tbl
- WHERE business_date = '20090201'
-
- 6) 索引列上使用 NULL 值
- IS NULL和IS NOT NULL会限制索引的使用,因为数据中没有值等于NULL值,即便是NULL值也不等于NULL值.且NULL值不存储在于索引之中
- 因此应尽可能避免在索引类上使用NULL值
-
- SELECT acc_num
- , pl_cd
- , order_qty
- , trade_date
- FROM trade_client_tbl
- WHERE input_date IS NOT NULL;
-
- Execution Plan
-
- Plan hash value: 901462645
-
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
- | 0 | SELECT STATEMENT | | 1 | 44 | 15 (0)| 00:00:01 |
- |* 1 | TABLE ACCESS FULL| TRADE_CLIENT_TBL | 1 | 44 | 15 (0)| 00:00:01 |
-
-
- alter table trade_client_tbl modify (input_date not null);
-
- 不推荐使用的查询方式
- SELECT * FROM table_name WHERE col IS NOT NULL
-
- SELECT * FROM table_name WHERE col IS NULL
-
- 推荐使用的方式
- SELECT * FROM table_name WHERE col >= 0
-
-
三、总结
1、尽可能最小化基表数据以及中间结果集(通过过滤条件避免后续产生不必要的计算与聚合)
2、为where子句中的谓词信息提供最佳的访问路径(rowid访问,索引访问)
3、使用合理的SQL写法来避免过多的Oracle内部开销以提高性能
4、合理的使用提示以提高表之间的连接来提高连接效率(如避免迪卡尔集,将不合理的嵌套连接改为hash连接等)
阅读(1420) | 评论(0) | 转发(1) |