`
wxyfighting
  • 浏览: 191776 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

ORACLE--预编译与共享池--SGA基本介绍

 
阅读更多

我们暂时先不说其他的,我们先做一个简单的实验来证明来看出一些问题,最后通过为什么来说明实验的结论,并介绍原理和常规查看方式,好了,我们先看看下面三段代码分别执行的结果。

首先为了测试,我们需要创建一张表:

CREATE TABLE PRE_TEST_TABLE(
C1 NUMBER,
C2 VARCHAR2(100)
);

好了,我们做一个插入操作的对比:

代码段1

BEGIN

FOR I IN 1..20000 LOOP

EXECUTE IMMEDIATE 'INSERT INTO PRE_TEST_TABLE VALUES('||i||',''test'')';

END LOOP;

COMMIT;

END;

代码片段2

BEGIN

FOR I IN 1..20000 LOOP

EXECUTE IMMEDIATE 'INSERT INTO PRE_TEST_TABLE VALUES(:V1,:V2)' USING I,'test';

END LOOP;

COMMIT;

END;

代码片段3

BEGIN

FOR I IN 1..20000 LOOP

INSERT INTO PRE_TEST_TABLE VALUES(I,'TEST');

END LOOP;

COMMIT;

END;

三段代码执行效率你可以清晰的对比出来,代码段1是最慢的,而且比后两者慢很多倍,而代码片段2和代码片段3执行效率基本是一样的,为什么会有这样的效果呢?看了下面的推敲,我们就清楚了,我们先把数据清理掉,共享池清理一下(下面我们再说),在做操作比较好。

现在我需要做的SQL语句操作是对表的插入PRE_TEST_TABLE VALUES表的操作:

INSERT INTO PRE_TEST_TABLE VALUES....

至于参数如何,我们不一定,首先查询一下共享池内部做此操作的记录:

SELECT * FROM V$SQLAREA
WHERE SQL_TEXT LIKE 'INSERT INTO PRE_TEST_TABLE VALUES%';

发现数据太多,有多少不好说了,暂时不数了,因为对得出结论没有意义,需要清理下共享池方便试验。

TRUNCATE TABLE PRE_TEST_TABLE;//清空表

ALTER SYSTEM FLUSH SHARED_POOL;//清空缓冲区

查询共享池:

SELECT * FROM V$SQLAREA
WHERE SQL_TEXT LIKE 'INSERT INTO PRE_TEST_TABLE VALUES%';

发现没有任何数据。。。。我们开始比较干净的做实验了。。。

开始试验:

我们将上述试验的循环次数降低为3

首先执行代码段1

BEGIN

FOR I IN 1..3 LOOP

EXECUTE IMMEDIATE 'INSERT INTO PRE_TEST_TABLE VALUES('||i||',''test'')';

END LOOP;

COMMIT;

END;

查询共享池(发现多了3条记录):

SQL> SELECT SQL_TEXT,HASH_VALUE,PARSE_CALLS FROM V$SQLAREA
2 WHERE SQL_TEXT LIKE 'INSERT INTO PRE_TEST_TABLE VALUES%';

SQL_TEXTHASH_VALUE PARSE_CALLS
--------------------------------------------------------------- -----------------------------------
INSERT INTO PRE_TEST_TABLE VALUES(1,'test')2868385396 1
INSERT INTO PRE_TEST_TABLE VALUES(2,'test')2513099158 1
INSERT INTO PRE_TEST_TABLE VALUES(3,'test')455953479 1

再执行第二段代码:

BEGIN

FOR I IN 1..3 LOOP

EXECUTE IMMEDIATE 'INSERT INTO PRE_TEST_TABLE VALUES(:V1,:V2)' USING I,'test';

END LOOP;

COMMIT;

END;

再查询共享池(发现只多了一条SQL):

SQL> SELECT SQL_TEXT,HASH_VALUE,PARSE_CALLS FROM V$SQLAREA
2 WHERE SQL_TEXT LIKE 'INSERT INTO PRE_TEST_TABLE VALUES%';

SQL_TEXTHASH_VALUE PARSE_CALLS
--------------------------------------------------------------- ---------------- ------------
INSERT INTO PRE_TEST_TABLE VALUES(1,'test')2868385396 1
INSERT INTO PRE_TEST_TABLE VALUES(:V1,:V2)357326048 3
INSERT INTO PRE_TEST_TABLE VALUES(2,'test')2513099158 1
INSERT INTO PRE_TEST_TABLE VALUES(3,'test')4559534791

再执行第三段代码:

BEGIN

FOR I IN 1..3 LOOP

INSERT INTO PRE_TEST_TABLE VALUES(I,'TEST');

END LOOP;

COMMIT;

END;

再查询共享池(发现也只多了一条SQL):

SQL> SELECT SQL_TEXT,HASH_VALUE,PARSE_CALLS FROM V$SQLAREA
2 WHERE SQL_TEXT LIKE 'INSERT INTO PRE_TEST_TABLE VALUES%';

SQL_TEXT HASH_VALUE PARSE_CALLS
------------------------------------------------------------- ------------------ ------------
INSERT INTO PRE_TEST_TABLE VALUES(1,'test')2868385396 1
INSERT INTO PRE_TEST_TABLE VALUES(:B1 ,'TEST')2239119514 3
INSERT INTO PRE_TEST_TABLE VALUES(:V1,:V2)357326048 3
INSERT INTO PRE_TEST_TABLE VALUES(2,'test')2513099158 1
INSERT INTO PRE_TEST_TABLE VALUES(3,'test') 455953479 1

从这里可能大家基本可以得出初步的结论,就是第一段代码每条SQL都会占用共享池,并征用共享池,而且用过一次后就不会在使用了,这个答案是正确的,我首先给出预编译和拼SQLORACLE的四个不同影响进行定义,下面再说明为什么:

1、拼SQL会导致共享池的长期征用状态

2、拼SQL会导致共享池中存在一堆的垃圾SQL

3、拼SQL会硬解析(Hard parse),而预编译可以充分利用软解析。

4、拼SQL会导致注入型错误。

疑问:

为什么第二段代码和第三段代码是一个效果呢,这里说明一下,在存储过程提高效率的基本因素就是你如果按照过程化去写SQL,存储过程默认就会按照预编译方式去执行,因为这是ORACLE优化的基本原则,而即使在过程中使用EXECUTE IMMEDIATE SQL_STR去执行,请注意,EXECUTE IMMEDIATE不是SQL语句,而是ORACLE在过程中支持的命令,即直接发送执行命令给ORACLE的分析器,所以这个是否进行编译完全看你的SQL是什么样的了,而不是ORACLE自己能决定的。

过程说明:

SQL从终端通过1521 TCP服务端口以字符串方式传送至ORACLE后(包含JAVA程序也是这样,其他应用程序,如出现String sql = "SELECT * FROM A WHERE ID="+id;也会出现和代码段1一样的结果),ORACLE通过HASH算法对其SQL转换,并在共享池中查找是否存在同样HASH值的SQL(即:SQL即使是参数或者大小写不同,也会导致找不到一样的HASH值),如果找到了,直接执行已经编译完的SQL,并修改使用率(这个有用);若没有,则首先通过硬解析工具对其进行各项语法分析和性能指标分析等等,然后开始征用共享池(此为共享资源),并注册到共享池中,标志调用次数为1,然后再执行,当在大量征用共享资源时候,并且在硬解析过程中,高并发将导致阻塞。可以将上述第一段代码的循环次数增加为10万,基本机器可以弄死,呵呵。。。。

共享池的大小肯定是有限制的,所以ORACLE在共享池不够用的时候,采用基于LRU为核心的算法进行替换(上述的PARSE_CALLS字段可以基本看出SQL被调用的次数,但是不完全依赖于它),我们最希望的就是不要做这样的操作,因为这样的操作必然面临磁盘读取,在内存中获取我们称为命中,命中率高才能提高利用率,系统的整体性能才能得到保证。

第四点中提到的至于注入型错误或攻击就是传送特殊字符串,导致SQL执行SQL的修改,为什么,因为你的SQL是拼出来的,我举个简单例子:

你的程序中:

String sql = "SELECT * FROM A WHERE A.NAME = '"+name+"'";

name假如为查询条件传入,那么此时我在查询条件文本框中这样输入:

第一种输入:

' OR 1=1--

此时你的SQL变成:

SELECT * FROM A WHERE A.NAME ='' OR 1=1 --'

后面两杠是屏蔽你后面的SQL,用一个OR 1=1前面的东东不论是啥就永远成立了(注意:ORACLE的SQL执行,优先级是AND大于 OR的,所以只要OR 1=1,无论有多少个AND,最后会和这个OR 1=1去匹配,所有的数据都会提取出来),此时分页或者说导出控制天数或者数据量,都控制不了,有多少数据就会出来多少数据,首先数据权限没有了,然后开几个浏览器系统就能挂掉,呵呵!

另一种更加损的输入招数是:

';DROP TABLE DUAL--

在我以前用SQL SERVERJDBC时,这种方式是支持的,这样是很损的一种办法。其实输入的方式有些通过URL有些通过条件,不一定,而且千奇百怪,有些想都想不到,至少他可能会导致你的SQL执行不是那么顺利篡改了SQL执行的原有意义。

所以OLTP系统使用这样的SQL,尤其对于ORACLE数据库(其余数据库请自己研究下),是非常恶心的,所以我们在OLTP系统是封杀这样的SQL存在。

简要共享池的使用介绍:

谈到共享池我们大致介绍一些SGA的内容,ORACLE数据库我们操作主要对象是实例,而非数据库本身,主要原因为:性能、安全性。而实例大致分:SGAPGA,本文只是由共享池介绍一下SGA,细节说下其共享池部分,而PGA后续讨论。

SGA内部主要包含:数据缓冲区、共享池、JAVA池、大池、Stream池、重做日志缓冲区

PGA内部包含:用户Session信息、排序信息、Hash area、堆栈。这些信息被后台进程所控制,版本递增的后台进程也在不断增加,细节的信息后续讨论。

其实今天所谓查询共享池,也是查询共享池内部的Library cache。我们在SQLPLUS中最常用的命令就是:

SQL> show sga;

Total System Global Area 1.7062E+10 bytes
Fixed Size 2102776 bytes
Variable Size 4613736968 bytes
Database Buffers 1.2432E+10 bytes
Redo Buffers 14671872 bytes

也可以使用一下方式查询和上述一样的SGA信息:

SQL> SELECT * FROM V$SGA;

NAME VALUE
-------------------- ----------
Fixed Size 2102776
Variable Size 4613736968
Database Buffers 1.2432E+10
Redo Buffers 14671872

分别解释下几个字段的意义:

Total System Global Area:代表SGA的总体大小,包含下面几者之和,都是以byte为单位,即字节;

Fixed Size:字典信息、控制信息、状态信息。

Variable Size共享池(shared pool)、Java(Java Pool)、大池(Large Pool)Stream pool

Database Buffers:为数据缓冲区,OLTP系统要求这块设置较大。

Redo Buffer:重做日志缓冲区,适当提高缓冲区,减少文件组切换,可以提高效率。

通过一下SQL可以得到SGA内部详细的组件分配情况:

SQL> SELECT * FROM V$SGASTAT;

POOL NAME BYTES
------------ -------------------------- ----------
fixed_sga 2102776
buffer_cache 1.2432E+10
log_buffer 14671872
shared pool transaction 8062512
shared pool table definiti 80336
shared pool KGSKI scheduler heap 2 de 232
shared pool kspd run-time context 16
shared pool PX subheap 61344
shared pool partitioning d 455480
shared pool message pool freequeue 757568
shared pool qesblGF:bfm 728

POOL NAME BYTES
------------ -------------------------- ----------

等等数据。。。。。。。自己查看一下即可,我这由于篇幅所限,就输出这么多了。

--下面SQL用于查看SGA中可进行手工调配参数的列表:

SQL> SELECT * FROM V$SGA_DYNAMIC_COMPONENTS;

COMPONENT CURRENT_SIZE MIN_SIZE MAX_SIZE USER_SPECIFIED_SIZE OPER_COUNT LAST_OPER_TYP LAST_
---------------------------------------------------------------- ------------ ---------- ----------
shared pool 4194304000 4194304000 0 4194304000 0 STATIC
large pool 134217728 134217728 0 134217728 0 STATIC
java pool 134217728 134217728 0 134217728 0 STATIC
streams pool 117440512 117440512 0 117440512 0 STATIC
DEFAULT buffer cache 1.2264E+10 1.2264E+10 0 1.2264E+10 2 SHRINK MANUAL 07-4

KEEP buffer cache 100663296 0 0 100663296 8 GROW MANUAL 07-4
-10
RECYCLE buffer cache 67108864 0 0 67108864 1 GROW MANUAL 07-4
-10
DEFAULT 2K buffer cache 0 0 0 0 0 STATIC
DEFAULT 4K buffer cache 0 0 0 0 0 STATIC
DEFAULT 8K buffer cache 0 0 0 0 0 STATIC
DEFAULT 16K buffer cache 0 0 0 0 0 STATIC

COMPONENT CURRENT_SIZE MIN_SIZE MAX_SIZE USER_SPECIFIED_SIZE OPER_COUNT LAST_OPER_TYP LAST_
---------------------------------------------------------------- ------------ ---------- ----------
DEFAULT 32K buffer cache 0 0 0 0 0 STATIC
ASM Buffer Cache 0 0 0 1.2465E+10 0 STATIC

查询共享池大小:

SQL> show parameter shared_pool_size;

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
shared_pool_size big integer 4000M

SQL> SELECT NAME,TYPE,VALUE
2 FROM V$PARAMETER A
3 WHERE A.NAME='shared_pool_size';

NAMETYPE VALUE
-------------------- ----------------------------- ----------------------------
shared_pool_size 6 4194304000

这里顺便说下,很多时候大家不知道数据字典是什么,很多时候数据字典的名字很长,而且有些后面又s,有些后面没有S,大家记录不下来,此时大家只需要知道大致是什么就OK了,然后用下面的基于视图的总视图去查询视图的实际名称(我们以不知道共享池的视图是什么):

SQL> SELECT * FROM DICT T
2 WHERE T.TABLE_NAME LIKE '%V$SHARED%';

TABLE_NAME COMMENTS
------------------------------ -------------------------------------------------------------------
V$SHARED_SERVER_MONITOR Synonym for V_$SHARED_SERVER_MONITOR
V$SHARED_SERVER Synonym for V_$SHARED_SERVER
V$SHARED_POOL_RESERVED Synonym for V_$SHARED_POOL_RESERVED
V$SHARED_POOL_ADVICE Synonym for V_$SHARED_POOL_ADVICE
GV$SHARED_SERVER_MONITORSynonym for GV_$SHARED_SERVER_MONITOR
GV$SHARED_SERVER Synonym for GV_$SHARED_SERVER
GV$SHARED_POOL_RESERVED Synonym for GV_$SHARED_POOL_RESERVED
GV$SHARED_POOL_ADVICE Synonym for GV_$SHARED_POOL_ADVICE

其中GV$开头的视图是用于集群中的,我们一般只关心V$开头的信息;可能你连表的大致意思都不清楚,你只大致记得有一个字段大致的名称,如我们知道一个视图内部字段的名称有一个以SCN开头的列,那么我们这样也可以反向给它定位:

SQL> SELECT T.TABLE_NAME, T.COLUMN_NAME
2 FROM DICT_COLUMNS T
3 WHERE T.COLUMN_NAME LIKE 'SCN%';

TABLE_NAME COLUMN_NAME
------------------------------ ------------------------------
ALL_SUMDELTA SCN
DBA_AUDIT_TRAIL SCN
USER_AUDIT_TRAIL SCN
DBA_AUDIT_STATEMENT SCN
USER_AUDIT_STATEMENT SCN
DBA_AUDIT_OBJECT SCN
USER_AUDIT_OBJECT SCN
DBA_AUDIT_EXISTS SCN
DBA_FGA_AUDIT_TRAIL SCN
DBA_COMMON_AUDIT_TRAIL SCN
DBA_CAPTURE_PREPARED_TABLES SCN
ALL_CAPTURE_PREPARED_TABLES SCN
DBA_FILE_GROUP_TABLES SCN
ALL_FILE_GROUP_TABLES SCN
USER_FILE_GROUP_TABLES SCN
V$RESTORE_POINT SCN
V$RECOVERY_STATUS SCN_NEEDED
V$LOGMNR_CONTENTS SCN
V$XML_AUDIT_TRAIL SCN
GV$RESTORE_POINT SCN

这里回到正题:清空共享池(OLTP系统运行时不要去操作,这个过程很影响整体运行)

SQL>ALTER SYSTEM FLUSH SHARED_POOL;

如果要查询某过程或包的源码,可以看一下系统的资源包:

SQL>SELECT * FROM USER_SOURCE t WHERE t.name = '过程或包的名字' ORDER BY LINE;

这些源码信息在首次是不会装入内存的,因为共享池的大小有限,调用时再装入内存,而且也不会逃脱LRU的命运,若一些写的很烂的SQL,就有可能把它替换出去,这个时候我们想做到的是启动时直接装入内存并不会被替换,ORACLE给我们一个KEEP方法,但是并非默认的,也就是安装ORACLE后并不是默认就提供的这个包,如果你用具有DBA权限的人进去,不能使用DBMS_SHARED_POOL这个包(报:这个包不存在),说明还没有创建,此时需要做一下操作,才能创建:

1、首先定位ORACLE_HOME的位置,我们没有直接定位ORACLE_HOME的方式,除非是你自己安装的,如果不知道,用下面一个办法:

SELECT * FROM V$PARAMETER P1
WHERE P1.NAME = 'spfile';

2、若没有该目录,使用CREATE SPFILE FROM PFILE;执行一下重启OK就有了,得到该目录后,假如得到如下:

D:/ORACLE10/PRODUCT/10.2.0/DB_1/DATABASE/SPFILEORCL102.ORA

那么ORACLE_HOME上相推两层得到:

D:/ORACLE10/PRODUCT/10.2.0/DB_1/

那么要得到那个包的创建脚本就在:

D:/oracle10/product/10.2.0/db_1/RDBMS/ADMIN/DBMSPOOL.SQL

此时需要到安装数据库的机器上去执行,如果你本地有脚本当然也可以执行,但是注意:这个执行必须是在SQLPLUS中,PL/SQL中执行该脚本不好用。

3、执行方式:进入到安装该数据库的SQLPLUS下用SYS用户登录,该包需要创建在SYS用户下。

SQL> @D:/oracle10/product/10.2.0/db_1/RDBMS/ADMIN/DBMSPOOL.SQL

程序包已创建。


授权成功。


视图已创建。


程序包体已创建。

4、对于系统的大过程,可能第一次装载比较缓慢,而且如果使用频率较高,可以将其脱离LRU算法,并直接装入内存,如果可以的话,做ORACLE启动时触发器,如果不行,就手动执行一下代码:

BEGIN

SYS.DBMS_SHARED_POOL.KEEP('存储过程或包的名字');

END;

若想将某过程从内存中去除掉:

BEGIN

SYS.DBMS_SHARED_POOL.UNKEEP('存储过程或包的名字');

END;

5、此时查看缓冲池中是否装载改对象:

SELECT name,owner,type
FROM v$db_object_cache where kept = 'YES'
AND NAME ='
过程或包的名字';//这个地方也可以用SQL片段来LIKE

查看共享池中执行的一些SQL包头:

SELECT * FROM V$SQLAREA;

通不过上述的SQL得到HASH_VALUE或者ADDREDSS或者SQL_ID都可以通过以下视图得到对应执行SQL的全部内容(当SQL较长的时候,V$SQLAREA只保存前面一部分,全部内容在该视图中):

SELECT * FROM V$SQLTEXT_WITH_NEWLINES;

得到SQL的执行计划:

SELECT * FROM V$SQL_PLAN;

得到对共享池设置的建议值,ORACLE根据实际运行情况,推荐值:

SELECT * FROM V$SHARED_POOL_ADVANCE;

还有些不是很常用的:

得到SQL绑定变量信息:

SELECT * FROM V$SQL_BIND_CAPTURE;

SQL占用共享池内存:

SELECT * FROM V$SQL_SHARED_MEMORY;

SQL消耗调用的统计信息:

SELECT * FROM V$SQLSTATS;

这里只是由预编译->共享池->SGA的过程,对于SGA的内核只是阐述了共享池的部分,下次说明SGA的另一大块,Data Buffer,数据缓冲区,该区域在OLTP系统中非常重要。

最后补充话题,本来这个想在后面说的,因为涉及一些其他内容,不过既然说到,就提一下吧,我们在OLTP要求使用绑定参数方式执行SQL如:

用应用程序的SQL应当是

String sql = “SELECT * FROM A WHERE ID=?”;

而不是

String sql = “SELECT * FROM A WHERE ID=”+id;

那么这样的情况我们该怎么办呢?当要查询多个ID,使用IN的情况,或者同时修改多条记录的操作,我们无疑想出最常规的三种办法(我们先介绍常规方法,再介绍解决问题的方法):

方法1(拼串,放弃预编译):

String sql = “SELECT * FROM A WHERE ID IN(”+keys+”)”;

付:该方法放弃预编译,但是也是常规方法中的无奈之举。

方法2(将参数个数动态化去预编译)

StringBuffer sql = new StringBuffer(256);

sql.append(“SEELCT * FROM A WHERE ID IN(”);

for(….) {

sql.append(“?”).append(“,”);

}

sql.deleteCharAt(sql.length()-1);

付:该方法比上一种稍微好一点,OLTP下一般情况下,我们常规方法中最少要这样去完成,大家可以把ibatis的执行SQL日志拿出来看下即可发现,ibatis对于动态参数个数也是这样去完成的,对于并发度不算高的代码段我们可以这样使用,如果并发度高的代码段,这样使用我们也不会考虑。

方法3(循环提取。循环修改)

for(….) {

ptmt.setInt(1,ID[i]);

ptmt.executeQuery(“SELECT * FROM A WHERE ID=?”);

}

付:这在执行过程中往往是最“不应该使用”的办法了;如果执行插入操作,我们会适当考虑携带批处理这样去完成也是可以的,不过对于UPDATE和SELECT这类操作我们不该这样使用的。

在这里上述三种办法,只有第二种方法OLTP并发量不大的情况下可以使用,若并发量较大,且参数个数的动态性比较大,也应该考虑使用其他方法去实现,因为大家通过上述试验和反向查询后发现,问号个数的变化也会产生不同的SQL,共享池中仍然会造成很多的垃圾,只是相对第一种方法概率降低了很多,而第三种方法基本是我们不考虑的。

我们说一下如果对于这样的情况,批量执行过程中,我们该如何转换,利用ORACLE的数组进行转换,为此我们先在ORACLE内部提供一个函数,和数组类型,前序工作:

步骤1

创建数据类型(表格类型,也类似数组):

CREATE OR REPLACE TYPE MY_TABLE_TYPE IS TABLE OF VARCHAR2(8000);

步骤2

创建转换函数(在网上很多地方可以找到类似代码,我这只是一个参考):

CREATE OR REPLACE FUNCTION SPLIT(SRC_STR IN VARCHAR2,

SPLIT_STR VARCHAR2) RETURN MY_TABLE_TYPEIS
V_TABLE_STR MY_TABLE_TYPE := MY_TABLE_TYPE();
V_TEMP_STR VARCHAR2(
8000) := SRC_STR;
V_SPLIT_STR VARCHAR2(
20) := SPLIT_STR;
I NUMBER :=
1;
J NUMBER :=
1;
BEGIN

IF V_SPLIT_STR IS NULL THEN
V_SPLIT_STR :=
',';--我们默认用逗号分隔
END IF;

IF SRC_STR IS NULL OR SRC_STR = V_SPLIT_STR THEN
RETURN V_TABLE_STR;
END IF;

V_TEMP_STR := LTRIM(V_TEMP_STR, V_SPLIT_STR);

LOOP
I := INSTR(V_TEMP_STR, V_SPLIT_STR, J);
EXIT WHEN I =
0 OR J > LENGTH(V_TEMP_STR);
V_TABLE_STR.EXTEND;
V_TABLE_STR(V_TABLE_STR.COUNT) := SUBSTR(V_TEMP_STR, J, I - J);
J := I + LENGTH(V_SPLIT_STR);
END LOOP;

IF J < LENGTH(V_TEMP_STR) THEN
V_TABLE_STR.EXTEND;
V_TABLE_STR(V_TABLE_STR.COUNT) := SUBSTR(V_TEMP_STR, J, LENGTH(V_TEMP_STR) - J +
1);
END IF;

RETURN V_TABLE_STR;

END SPLIT;

步骤3:(测试可用性,这里假如数据都是按照逗号分隔的)

较高版本支持这样的写法:

SQL> SELECT * FROM TABLE(SPLIT('123,321',','));

COLUMN_VALUE

--------------------------------------------------------------------------------

123

321

较低版本可以这样写:

SQL> SELECT * FROM TABLE(CAST(SPLIT('123,321,456', ',') AS MY_TABLE_TYPE));

COLUMN_VALUE

--------------------------------------------------------------------------------

123

321

456

步骤4(程序应用):

String sql = “SELECT * FROM A WHERE ID IN(SELECT * FROM TABLE(SPLIT(?,',')))”;//当然对于低版本的数据库,相应修改即可。

但是ORACLE有些时候会很傻的去使用HASH JOIN,因为他们他不知道你里面返回多少数据,而我们通过转换回来的ID往往数据量很少,最多就是几十行上百行,若目标表为一个大表,使用HASH JOIN的确是一件很浪费的事情,此时我们不愿意这样去做,因为很浪费CPU和临时表空间(这其实是后面要说的),我们一般需要强制指定查询的方式来控制他走嵌套循环,让大表根据小表去走索引,使用ORACLEHint来强制告诉它应该由小表引导大表执行,来保证SQL执行计划的稳定性:

String sql = “SELECT /*+ordered use_nl(a2,a1)*/a2.* FROM A a1,(SELECT COLUMN_VALUE FROM TABLE(SPLIT(?,',')) a2 WHERE a1.ID = A2.COLUMN_VALUE”;

此时可能会问,这样转一次会不会很慢,是的,这不难会想想一个拆开字符串的过程,我们必然会消耗一点,不过要想到一次执行就是拆开一个字符串而已,而且我们传入的字符串也不会太长,这个解析过程对于ORACLE来说还是没啥问题的,不必担心这个,而更加重要的提高了共享池的应用。

分享到:
评论

相关推荐

    SGA - ORACLE

    1. 本文系作者的学习总结总(参考文档来自ORACLE官方文档) 2. 介绍了ORACLE中SGA的基本概念与样关内存区的的分配基本原则

    oracle-sga结构

    oracle sga 结构的讲解,了解oracle的sga结构。

    ORACLE-SGA.docx

    .

    Oracle_SGA

    有关Oracle的SGA基本组件与概述 如共享池的作用、使用方式等

    Oracle认证专家视频教程-OCP全套教程-共98个视频

    03-042-1-4-sga-shared_pool.mp4 03-042-1-5-sga-data_buffer.mp4 03-042-1-6-sga-log_buffer.mp4 03-042-1-7-sga-large_poolmp4 03-042-1-8-sga-others_pool.mp4 03-042-1-9-bcakground-process.mp4 03-042-1-10-bg...

    Oracle SGA

    关于Oracle 中SGA的分配的方式,如何让oracle中的SGAt得到最有利的分配

    oracle sga设置

    oracle sga常用设置,分析,查看等等.

    oracle改sga导致数据库启动异常处理办法

    有时改oracle的sga相关值后,重启oracle出现异常。 其实更改sga前掌握好先备份的原则,就能快速恢复

    ORACLE修改SGA后无法启动的临时解决方法

    ORACLE修改SGA后无法启动的临时解决方法.比较实用的东西

    Oracle 9i 调整SGA性能

    调整SGA以及优化oracle数据库,提高数据库的性能。

    更改ORACLE SGA的详细步骤

    更改ORACLE SGA的详细步骤 如果修改后启动不了ORACLE,还原ORACLE初始设置的方法方法: 2、使用dos端登录oracle Sqlplus /nolog; Conn / as sysdba; 3、找 pfile,在 /.../admin/XXX(服务名)/pfile 下,init.ora....

    oracle SGA PGA UGA 内存

    oracle SGA PGA UGA 内存的概念; UGA和PGA不是一回事; UGA包含了对Oracle共享服务器的会话信息。当oracle的服务采用共享服务器会话模式而没有配置大池时, UGA就位于使用的共享池中。

    Oracle 体系结构-SGA

    Oracle数据库由两部分组成:实例和数据库 实例是由一块共享内存区域以及一些后台进程组成。 1.SGA SGA为共享内存区域,也叫系统全局区 SGA的特点: -是共享的,是所有使用当前实例的用户都可以读取的内存部分。 -一...

    MATLAB算法实战应用案例精讲-搜索组算法 - SGA-MATLAB实现源代码

    MATLAB算法实战应用案例精讲-搜索组算法 - SGA-MATLAB实现源代码

    oracle Sga调优

    oracle 的sga调优的一些很好的规则,共同参考,一起进步吧!

    Oracle_Database10g_性能调整与优化-第10章_使用PLSQL提高性能

    当PL/SQL被传递给Oracle之后,通常是放置在Oracle的系统全局区(SGA)中,特殊情况下会放置在共享池内。在Oracle中,PL/SQL的源代码可以以过程、函数、数据包,或者触发器的形式被存储在数据库中。一旦这些对象以编译...

    Oracle-数据库简答题.doc

    第一章 简答题 1.简述Oracle数据库逻辑结构中各元素之间的关系。 答:数据库由若干个表空间组成,表空间由表、索引、视图等逻辑对象组成,表由段 组成,段由区组成,区则由数据块组成... 答:SGA是一组共享内存结构,

    sga调整过大oracle无法启动解决方案

    sga调整过大oracle无法启动解决方案文档记录了LINUX环境下将ORACLE的SGA设置过大导致数据库无法启动的解决方案

    oracle10g课堂练习II(1)

    共享池 8-10 大型池 8-11 Java 池 8-12 重做日志缓冲区 8-13 自动管理共享内存:概览 8-14 自动管理共享内存的好处 8-15 ASMM 的工作原理 8-16 使用 Database Control 配置 ASMM 8-17 手动配置 ASMM 8-18 ...

    oracle实例内存(SGA和PGA)分析与调整.docx

    oracle实例内存(SGA和PGA)分析与调整

Global site tag (gtag.js) - Google Analytics