Oracle SQL执行计划与优化

系统函数Userenv

Oracle中USERENV和SYS_CONTEXT用来返回当前session的信息,其中,userenv是为了保持向下兼容的遗留函数,推荐使用sys_context函数调用userenv命名空间来获取相关信息。

1、 USERENV(OPTION)
  返回当前的会话信息.
  OPTION='ISDBA'若当前是DBA角色,则为TRUE,否则FALSE.
  OPTION='LANGUAGE'返回数据库的字符集.
  OPTION='SESSIONID'为当前会话标识符.
  OPTION='ENTRYID'返回可审计的会话标识符.
  OPTION='LANG'返回会话语言名称的ISO简记.
  OPTION='INSTANCE'返回当前的实例.
OPTION='terminal'返回当前计算机名
  SELECT USERENV('LANGUAGE') FROM DUAL;

2、sys_context
select
SYS_CONTEXT('USERENV','TERMINAL') terminal,
SYS_CONTEXT('USERENV','LANGUAGE') language,
SYS_CONTEXT('USERENV','SESSIONID') sessionid,
SYS_CONTEXT('USERENV','INSTANCE') instance,
SYS_CONTEXT('USERENV','ENTRYID') entryid,
SYS_CONTEXT('USERENV','ISDBA') isdba,
SYS_CONTEXT('USERENV','NLS_TERRITORY') nls_territory,
SYS_CONTEXT('USERENV','NLS_CURRENCY') nls_currency,
SYS_CONTEXT('USERENV','NLS_CALENDAR') nls_calendar,
SYS_CONTEXT('USERENV','NLS_DATE_FORMAT') nls_date_format,
SYS_CONTEXT('USERENV','NLS_DATE_LANGUAGE') nls_date_language,
SYS_CONTEXT('USERENV','NLS_SORT') nls_sort,
SYS_CONTEXT('USERENV','CURRENT_USER') current_user,
SYS_CONTEXT('USERENV','CURRENT_USERID') current_userid,
SYS_CONTEXT('USERENV','SESSION_USER') session_user,
SYS_CONTEXT('USERENV','SESSION_USERID') session_userid,
SYS_CONTEXT('USERENV','PROXY_USER') proxy_user,
SYS_CONTEXT('USERENV','PROXY_USERID') proxy_userid,
SYS_CONTEXT('USERENV','DB_DOMAIN') db_domain,
SYS_CONTEXT('USERENV','DB_NAME') db_name,
SYS_CONTEXT('USERENV','HOST') host,
SYS_CONTEXT('USERENV','OS_USER') os_user,
SYS_CONTEXT('USERENV','EXTERNAL_NAME') external_name,
SYS_CONTEXT('USERENV','IP_ADDRESS') ip_address,
SYS_CONTEXT('USERENV','NETWORK_PROTOCOL') network_protocol,
SYS_CONTEXT('USERENV','BG_JOB_ID') bg_job_id,
SYS_CONTEXT('USERENV','FG_JOB_ID') fg_job_id,
SYS_CONTEXT('USERENV','AUTHENTICATION_TYPE') authentication_type,
SYS_CONTEXT('USERENV','AUTHENTICATION_DATA') authentication_data
from dual


ROWID、ROWNUM

认识ROWID
SQL> select rowid from dept where rownum < 2;

ROWID各列信息格式如下

数据对象编号        文件编号        块编号           行编号
OOOOOO             FFF               BBBBBB         RRR

简单查看ROWID信息
select rowid ,
  substr(rowid,1,6) "OBJECT",
  substr(rowid,7,3) "FILE",
  substr(rowid,10,6) "BLOCK",
  substr(rowid,16,3) "ROW"
from dept
/

ROWNUM是oracle系统顺序分配为从查询返回的行的编号。
返回的第一行分配的是1,第二行是2,依此类推。
这个伪字段可以用于限制查询返回的总行数,且rownum不能以任何表的名称作为前缀。


分析Oracle索引扫描四大类

学习Oracle时,你可能会遇到Oracle索引扫描问题,这里将介绍Oracle索引扫描问题的解决方法,在这里拿出来和大家分享一下。根据索引的类型与where限制条件的不同,有4种类型的Oracle索引扫描:

◆索引唯一扫描(index unique scan)
◆索引范围扫描(index range scan)
◆索引全扫描(index full scan)
◆索引快速扫描(index fast full scan)

(1) 索引唯一扫描(index unique scan)

通过唯一索引查找一个数值经常返回单个ROWID。如果该唯一索引有多个列组成(即组合索引),则至少要有组合索引的引导列参与到该查询中,如创建一个索引:create index idx_test on emp(ename, deptno, loc)。则select ename from emp where ename = ‘JACK’ and deptno = ‘DEV’语句可以使用该索引。如果该语句只返回一行,则存取方法称为索引唯一扫描。而select ename from emp where deptno = ‘DEV’语句则不会使用该索引,因为where子句种没有引导列。如果存在UNIQUE 或PRIMARY KEY 约束(它保证了语句只存取单行)的话,Oracle经常实现唯一性扫描。

使用唯一性约束的例子:

    SQL> explain plan for  
    select empno,ename from emp where empno=10;  
    Query Plan  
    SELECT STATEMENT [CHOOSE] Cost=1 
    TABLE ACCESS BY ROWID EMP [ANALYZED]  
    INDEX UNIQUE SCAN EMP_I1 

(2) 索引范围扫描(index range scan)

使用一个索引存取多行数据,同上面一样,如果索引是组合索引,如(1)所示,而且select ename from emp where ename = ‘JACK’ and deptno = ‘DEV’语句返回多行数据,虽然该语句还是使用该组合索引进行查询,可此时的存取方法称为索引范围扫描。在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符(如>、<、<>、>=、<=、between)

使用索引范围扫描的例子:

    SQL> explain plan for select empno,ename from emp  
    where empno > 7876 order by empno;  
    Query Plan  
    SELECT STATEMENT [CHOOSE] Cost=1 
    TABLE ACCESS BY ROWID EMP [ANALYZED]  
    INDEX RANGE SCAN EMP_I1 [ANALYZED] 

在非唯一索引上,谓词col = 5可能返回多行数据,所以在非唯一索引上都使用索引范围扫描。

使用index rang scan的3种情况:
(a) 在唯一索引列上使用了range操作符(> < <> >= <= between)
(b) 在组合索引上,只使用部分列进行查询,导致查询出多行
(c) 对非唯一索引列上进行的任何查询。

(3) 索引全扫描(index full scan)

与全表扫描对应,也有相应的全Oracle索引扫描。在某些情况下,可能进行全Oracle索引扫描而不是范围扫描,需要注意的是全Oracle索引扫描只在CBO模式下才有效。 CBO根据统计数值得知进行全Oracle索引扫描比进行全表扫描更有效时,才进行全Oracle索引扫描,而且此时查询出的数据都必须从索引中可以直接得到。

全Oracle索引扫描的例子:

    An Index full scan will not perform single block i/o's and so it may prove to be inefficient.  
    e.g.  
    Index BE_IX is a concatenated index on big_emp (empno, ename)  
    SQL> explain plan for select empno, ename from big_emp order by empno,ename;  
    Query Plan  
    SELECT STATEMENT [CHOOSE] Cost=26 
    INDEX FULL SCAN BE_IX [ANALYZED] 

(4) 索引快速扫描(index fast full scan)

扫描索引中的所有的数据块,与 index full scan很类似,但是一个显著的区别就是它不对查询出的数据进行排序,即数据不是以排序顺序被返回。在这种存取方法中,可以使用多块读功能,也可以使用并行读入,以便获得最大吞吐量与缩短执行时间。

索引快速扫描的例子:

    SQL> explain plan for select empno,ename from big_emp;  
    Query Plan  
    SELECT STATEMENT [CHOOSE] Cost=1 
    INDEX FAST FULL SCAN BE_IX [ANALYZED]  
    SQL> explain plan for select ename from big_emp;  
    Query Plan  
    SELECT STATEMENT [CHOOSE] Cost=1 
    INDEX FAST FULL SCAN BE_IX [ANALYZED] 

DML语句-CALL

測試oracle直接call java程式
當初oracle提供這個功能是為了讓java的程式師可方便寫的一些功能在oracle中使用,這樣子也就可不必學pl/sql了
但我暫時還沒有找到效能上的差別是多少的官方資料。
不過有做過就記錄一下,以免以後真的遇到還要上網找資料


1、先寫一個很簡單的java程式 (檔名叫 test.java,請注意大小寫)
public class test
{
    public static void main(String[] a) {
        System.out.println("this is java");
    }
}

2、編譯成class
D:\>javac test.java

3、查看一下是否ok
D:\>dir test.*
磁碟區 D 中的磁碟是 本機磁碟
磁碟區序號: 7098-7819

目錄: D:\

2007-03-14 11:38a                 414 test.class
2007-03-14 11:37a                 120 test.java
               2 個檔案             534 位元組
               0 個目錄   9,290,588,160 位元組可用

4、進sqlplus了
D:\>sqlplus sys/binhu as sysdba

SQL*Plus: Release 10.2.0.1.0 - Production on 星期三 3月 14 11:41:20 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

連線至閒置的執行處理.

SQL> startup
ORACLE 執行處理已啟動.

Total System Global Area 201326592 bytes
Fixed Size                  1248092 bytes
Variable Size              92275876 bytes
Database Buffers          104857600 bytes
Redo Buffers                2945024 bytes
資料庫已掛載.
資料庫已開啟.

5、建立相關的別名跟設定
SQL> create or replace directory java_dir as 'd:\';

已建立目錄.

SQL> create or replace java class using bfile(java_dir,'test.class');
2 /

已建立 Java.

SQL> create or replace procedure test_java as language java name 'test.main(java.lang.String[])';
2 /

已建立程序.

6、準備測試了
SQL> set serveroutput on size 2000
SQL> call dbms_java.set_output(2000);

已完成呼叫.

SQL> execute test_java;
this is java

已順利完成 PL/SQL 程序.

SQL> call test_java();
this is java

已完成呼叫.


心得:
使用上還算簡單,但真正上線的db會有多少人讓java在上面跑呢,因為這又多了一個變數
到時db掛了,還要多花心力去查看是否是由java引起的問題=.="
除非oracle有大力推行跟公司有規定使用的話,不然我還是不會讓java跑在db上的,呵呵

-bash-3.00$ pwd
/export/home/oracle

-bash-3.00$ vi test.java
"test.java"[新文件] 
public class test
{
    public static void main(String[] a) {
        System.out.println("this is java");
    }
}

-bash-3.00$ javac test.java

-bash-3.00$ sqlplus / as sysdba

SQL> create or replace directory java_dir as '/export/home/oracle';
Directory created.

SQL> create or replace java class using bfile(java_dir,'test.class');
Java created.

SQL> create or replace procedure test_java as language java name 'test.main(java.lang.String[])';
Procedure created.

SQL> set serveroutput on size 2000
SQL> call dbms_java.set_output(2000);

已完成呼叫.

SQL> execute test_java;
this is java

已順利完成 PL/SQL 程序.

SQL> call test_java();
this is java




ERROR at line 1:
ORA-29516: Aurora assertion failure: Assertion failure at eox.c:317
Uncaught exception System error:   java/lang/UnsupportedClassVersionError
根据http://edu.136z.com/DataBase/27839.html的解决方法

设置了LD_LIBRARY_PATH,

SQL> CALL SGRADE(:sgrade) INTO :output

SQL> print output
调用完全正确 


DML语句-MERGE

     把数据从一个表复制到另一个表,插入新数据或替换掉老数据是每一个ORACLE DBA都会经常碰到的问题。
     在ORACLE9i以前的年代,我们要先查找是否存在老数据,如果有用UPDATE替换,否则用INSERT语句插入,其间少不了还有一些标记变量等等,繁琐的很。
     现在ORACLE9i专为这种情况提供了MERGE语句,使这一工作变得异常轻松,Oracle9i引入了MERGE命令,你能够在一个SQL语句中对一个表同时执行inserts和updates操作. MERGE命令从一个或多个数据源中选择行来updating或inserting到一个或多个表.

Oracle 10g中MERGE有如下一些改进:

1、UPDATE或INSERT子句是可选的
2、UPDATE和INSERT子句可以加WHERE子句
3、ON条件中使用常量过滤谓词来insert所有的行到目标表中,不需要连接源表和目标表
4、UPDATE子句后面可以跟DELETE子句来去除一些不需要的行

首先创建示例表:

create table PRODUCTS
    (
    PRODUCT_ID INTEGER,
    PRODUCT_NAME VARCHAR2(60),
    CATEGORY VARCHAR2(60)
    );

    insert into PRODUCTS values (1501, 'VIVITAR 35MM', 'ELECTRNCS');
    insert into PRODUCTS values (1502, 'OLYMPUS IS50', 'ELECTRNCS');
    insert into PRODUCTS values (1600, 'PLAY GYM', 'TOYS');
    insert into PRODUCTS values (1601, 'LAMAZE', 'TOYS');
    insert into PRODUCTS values (1666, 'HARRY POTTER', 'DVD');
    commit;

 create table NEWPRODUCTS
    (
    PRODUCT_ID INTEGER,
    PRODUCT_NAME VARCHAR2(60),
    CATEGORY VARCHAR2(60)
    );

    insert into NEWPRODUCTS values (1502, 'OLYMPUS CAMERA', 'ELECTRNCS');
    insert into NEWPRODUCTS values (1601, 'LAMAZE', 'TOYS');
    insert into NEWPRODUCTS values (1666, 'HARRY POTTER', 'TOYS');
    insert into NEWPRODUCTS values (1700, 'WAIT INTERFACE', 'BOOKS');
    commit;


1、可省略的UPDATE或INSERT子句

     在Oracle 9i, MERGE语句要求你必须同时指定INSERT和UPDATE子句.而在Oracle 10g, 你可以省略UPDATE或INSERT子句中的一个. 下面的例子根据表NEWPRODUCTS的PRODUCT_ID字段是否匹配来updates表PRODUCTS的信息:

MERGE INTO products p
    USING newproducts np
    ON (p.product_id = np.product_id)
    WHEN MATCHED THEN
    UPDATE
    SET p.product_name = np.product_name,
        p.category = np.category
/

    SQL> SELECT * FROM products;

    PRODUCT_ID PRODUCT_NAME CATEGORY
    ---------- -------------------- ----------
    1501 VIVITAR 35MM ELECTRNCS
    1502 OLYMPUS CAMERA ELECTRNCS
    1600 PLAY GYM TOYS
    1601 LAMAZE TOYS
    1666 HARRY POTTER TOYS
    SQL>
    SQL> ROLLBACK;
    Rollback complete.
    SQL>

     在上面例子中, MERGE语句影响到是产品id为1502, 1601和1666的行. 它们的产品名字和种 类被更新为表newproducts中的值. 下面例子省略UPDATE子句, 把表NEWPRODUCTS中新的PRODUCT_ID插入到表PRODUCTS中, 对于在两个表中能够匹配上PRODUCT_ID的数据不作任何处理. 从这个例子你能看到PRODUCT_ID=1700的行被插入到表PRODUCTS中.

SQL> MERGE INTO products p
    2 USING newproducts np
    3 ON (p.product_id = np.product_id)
    4 WHEN NOT MATCHED THEN
    5 INSERT
    6 VALUES (np.product_id, np.product_name,
    7 np.category);

    1 row merged.

    SQL> SELECT * FROM products;

    PRODUCT_ID PRODUCT_NAME CATEGORY
    ---------- -------------------- ----------
    1501 VIVITAR 35MM ELECTRNCS
    1502 OLYMPUS IS50 ELECTRNCS
    1600 PLAY GYM TOYS
    1601 LAMAZE TOYS
    1666 HARRY POTTER DVD
    1700 WAIT INTERFACE BOOKS

2、带条件的Updates和Inserts子句

你能够添加WHERE子句到UPDATE或INSERT子句中去,
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值