java缓存和数据池.docx
- 文档编号:9309257
- 上传时间:2023-05-18
- 格式:DOCX
- 页数:30
- 大小:44.93KB
java缓存和数据池.docx
《java缓存和数据池.docx》由会员分享,可在线阅读,更多相关《java缓存和数据池.docx(30页珍藏版)》请在冰点文库上搜索。
java缓存和数据池
Oracle数据库11g:
面向DBA和开发人员的重要新特性
作者:
ArupNanda
缓存和连接池
探究如何使用SQL结果缓存、PL/SQL功能缓存和客户端缓存以及数据库驻留连接池来改善性能。
下载Oracle数据库11g
SQL结果缓存
访问内存比访问硬盘快得多,在接下来几年中,除非硬盘体系结构有重大改进,不然这一情况很可能会持续。
缓存这一将数据存储于内存而非硬盘中的过程由此应运而生。
缓存是Oracle数据库体系结构的一个基本原理,用户从缓存而非数据库所驻留的磁盘中获取数据。
在相对较小的含静态数据的表中,如STATES、PRODUCT_CODES等参考表,缓存的优势异乎寻常的明显。
但是,假设有一个存储公司客户的大型表CUSTOMERS。
列表相对静态但不完全是,在向列表中添加或从列表中删除客户时,表极少更改。
缓存在这一情况中也有些许用武之地。
但如果您要缓存该表,如何在发生变化时确保获得正确的数据?
Oracle数据库11g 可以解决这一问题:
使用QL结果缓存。
假设查询如下。
运行它以获取执行统计信息和响应时间:
SQL>setautotonexplainstat
select
state_code,
count(*),
min(times_purchased),
avg(times_purchased)
fromcustomers
groupbystate_code
/
结果是:
STCOUNT(*)MIN(TIMES_PURCHASED)AVG(TIMES_PURCHASED)
----------------------------------------------------
NJ11515
NY994898015.0052086
CT5099014.9466562
MO12525
FL133
5rowsselected.
Elapsed:
00:
00:
02.57
ExecutionPlan
----------------------------------------------------------
Planhashvalue:
1577413243
--------------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
--------------------------------------------------------------------------------
|0|SELECTSTATEMENT||5|30|1846(25)|00:
00:
23|
|1|HASHGROUPBY||5|30|1846(25)|00:
00:
23|
|2|TABLEACCESSFULL|CUSTOMERS|1000K|5859K|1495(7)|00:
00:
18|
--------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
1recursivecalls
0dbblockgets
5136consistentgets
5128physicalreads
0redosize
760bytessentviaSQL*Nettoclient
420bytesreceivedviaSQL*Netfromclient
2SQL*Netroundtripsto/fromclient
0sorts(memory)
0sorts(disk)
5rowsprocessed
几点注意事项:
∙解释计划说明执行了全表扫描。
∙共有5,136次连续的获取(逻辑I/O)。
∙执行时间2.57秒。
因为表几乎没变,您可以使用提示来存储要缓存到内存中的查询结果:
select/*+result_cache*/
state_code,
count(*),
min(times_purchased),
avg(times_purchased)
fromcustomers
groupbystate_code
/
除提示外,查询与第一个相同。
结果(第二次执行该查询):
STCOUNT(*)MIN(TIMES_PURCHASED)AVG(TIMES_PURCHASED)
----------------------------------------------------
NJ11515
NY994898015.0052086
CT5099014.9466562
MO12525
FL133
5rowsselected.
Elapsed:
00:
00:
00.01
ExecutionPlan
----------------------------------------------------------
Planhashvalue:
1577413243
--------------------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
--------------------------------------------------------------------------------------
|0|SELECTSTATEMENT||5|30|1846(25)|00:
00:
23|
|1|RESULTCACHE|gk69saf6h3ujx|||||
|||525twvvsnaytd|||||
|2|HASHGROUPBY||5|30|1846(25)|00:
00:
23|
|3|TABLEACCESSFULL|CUSTOMERS|1000K|5859K|1495(7)|00:
00:
18|
--------------------------------------------------------------------------------------
ResultCacheInformation(identifiedbyoperationid):
------------------------------------------------------
1-column-count=4;dependencies=(ARUP.CUSTOMERS);parameters=(nls);name="select/*+result_cache*/
state_code,
count(*),
min(times_purchased),
avg(times_purchased)
fromcustomers
groupbystate_c"
Statistics
----------------------------------------------------------
0recursivecalls
0dbblockgets
0consistentgets
0physicalreads
0redosize
760bytessentviaSQL*Nettoclient
420bytesreceivedviaSQL*Netfromclient
2SQL*Netroundtripsto/fromclient
0sorts(memory)
0sorts(disk)
5rowsprocessed
注意与第一次的不同之处。
∙响应时间现在为0.01秒,而不是先前的将近3秒。
∙连续的获取为0,这一查询没有执行逻辑I/O。
(事实上,首次运行带有提示的查询时,I/O将保持不变,因为数据库需要执行I/O来构建缓存。
后续的调用将从缓存中供应数据,从而消除了I/O。
)
∙这一解释计划将RESULTCACHE视为一个操作。
∙解释计划的注意事项指明执行的缓存类型以及缓存结果。
在时间上的节约是显著的:
从3秒到几乎为0!
这是因为第二次查询使用了缓存,结果直接来自数据库内存(结果缓存)而不是执行查询。
SQL结果缓存是SGA中的另一个缓存,与缓冲区缓存或程序全局区一样。
当您执行带有result_cache提示的查询时,Oracle执行该操作的过程与其他操作一样,只是结果存储在SQL结果缓存中。
接下来对同一查询的调用将不访问表,而是从缓存中获取结果。
缓存大小由几个初始化参数确定:
参数
说明
result_cache_max_size
结果缓存上限(例如,5M上限)。
如果将它设为0,将完全关闭结果缓存。
result_cache_max_result
指定任一结果可使用的result_cache_max_size百分比
result_cache_mode
如设置为FORCE,如果缓存可以容纳所有查询,就会缓存它们。
默认值为MANUAL表示只缓存带有提示的查询。
result_cache_remote_expiration
指定访问远程对象的缓存结果保持有效的时间(以分钟为单位)。
默认为0。
现在,有一个逻辑问题:
当表行更改时,将发生什么情况?
查询将获取新值还是旧值?
好,让我们来看一看。
从另一个SQL*Plus会话更新表中的某一行:
SQL>updatecustomerssettimes_purchased=4
2wherestate_code='FL';
1rowupdated.
但是不要提交。
在首次运行查询的原窗口中,再运行一次。
使用的是仍是缓存结果,因为更改没有提交。
运行查询的会话仍然查看最新版本的数据,缓存仍旧有效。
现在,从您进行更新操作的会话中,发出提交指令,然后运行查询。
STCOUNT(*)MIN(TIMES_PURCHASED)AVG(TIMES_PURCHASED)
----------------------------------------------------
NJ11515
NY994898015.0052086
CT5099014.9466562
MO12525
FL144
注意FL的数据自动更新为4。
底层表的更改致使缓存无效,因而在下一次查询它时将动态更新。
无论您是否使用SQL结果缓存,都能保证获得正确的结果。
差异与物化视图
熟悉物化视图(MV)的人可能想这一功能与MV的功能有什么区别。
答案是:
有很多区别。
表面上他们很相似,都是用某种方法保存结果,从保存的数据集中提供答案,但他们的相似之处也仅限于此了。
MV将数据保存在数据库存储中,而SQL结果缓存位于内存中。
它们不使用更多的磁盘空间,当数据库实例关闭后,它们会消失,或者result_cache中的磁盘空间将耗尽。
MV也是静态的,当底层表中的数据更改时,MV并不知道。
除非您刷新MV,否则在您将query_rewrite_integrity设为stale_tolerated的情况下,用户可能获得的是旧数据,或者用户需要针对底层表重新运行基本查询,而这将花费更多的时间。
使用SQL结果缓存,您不需要显式刷新缓存;下一次运行查询时,缓存将自动刷新。
MV提供了一个更为复杂的重写算法。
首次对结果进行缓存后,只有重新运行同一查询或查询片段时才会重用缓存的结果(且底层数据未更改)。
受益于对MV进行查询重写的查询仍可从物化视图上卷数据,联结回表或其他物化视图,并应用其他谓词,这是数据仓库环境中很重要的一个特点。
因此,MV和SQL结果缓存是不可比或不可互换的,它们各具千秋。
子查询
您也能在子查询中使用SQL结果缓存。
请看以下查询:
selectprod_subcategory,revenue
from(
select/*+result_cache*/p.prod_category,
p.prod_subcategory,
sum(s.amount_sold)revenue
fromproductsp,saless
wheres.prod_id=p.prod_id
ands.time_idbetweento_date('01-jan-1990','dd-mon-yyyy')
andto_date('31-dec-2007','dd-mon-yyyy')
groupbyrollup(p.prod_category,p.prod_subcategory)
)
whereprod_category='software/other'
/
在上面的查询中,缓存发生在内联视图的子查询中。
因此,只要内联查询保持不变,外部查询就可以更改且可使用缓存。
要检查有多少内存用于数据库中的SQL结果缓存,您可以使用提供的程序包dbms_result_cache,如下所示:
SQL>setserveroutputonsize999999
SQL>executedbms_result_cache.memory_report
ResultCacheMemoryReport
[Parameters]
BlockSize=1Kbytes
MaximumCacheSize=2560Kbytes(2560blocks)
MaximumResultSize=128Kbytes(128blocks)
[Memory]
TotalMemory=126736bytes[0.041%oftheSharedPool]
...FixedMemory=5132bytes[0.002%oftheSharedPool]
...DynamicMemory=121604bytes[0.040%oftheSharedPool]
.......Overhead=88836bytes
.......CacheMemory=32Kbytes(32blocks)
...........UnusedMemory=21blocks
...........UsedMemory=11blocks
...............Dependencies=4blocks(4count)
...............Results=7blocks
...................SQL=5blocks(4count)
...................Invalid=2blocks(2count)
PL/SQLproceduresuccessfullycompleted.
如果您因故想清空缓存(包括结果缓存和功能缓存,如下描述),可以使用:
begin
dbms_result_cache.flush;
end;
执行以上命令后,通过result_cache提示对CUSTOMERS运行原始查询后,您将再次看到查询需要3秒完成。
当然,第一次运行后,结果将再次缓存,后续执行将从结果缓存中获取值,因此执行速度将更快。
如果您只想使一个表的缓存无效,而不是整个缓存,可以使用以下命令:
begin
dbms_result_cache.invalidate('ARUP','CUSTOMERS');
end;
有几个数据词典视图列出了SQL结果缓存的统计数据:
视图
说明
V$RESULT_CACHE_STATISTICS
显示不同的设置,特别是内存使用
V$RESULT_CACHE_MEMORY
显示组成SQL结果缓存的各内存块
V$RESULT_CACHE_OBJECTS
显示组成SQL结果缓存的对象
V$RESULT_CACHE_DEPENDENCY
显示组成SQL结果缓存的各个对象间的依赖关系
SQL结果缓存使您能够缓存访问大量数据的查询的结果。
当底层表更改时,如果您没有干预或另外编写代码,缓存将自动失效。
PL/SQL功能结果缓存
假设您使用一个PL/SQL函数(而不是SQL查询)来返回值。
这种使用函数返回值来构造代码模块的做法很常见。
假设有两个表:
CUSTOMERS存储所有客户的信息以及state_code。
另一个表TAX_RATE存储每个州的税率。
要获得适用于客户的税率,您需要在查询中联结表。
因此,为简化这一过程,您打算编写如下函数,以接受客户ID作为参数,并基于state_code返回相应的税率:
createorreplacefunctionget_tax_rate
(
p_cust_idcustomers.cust_id%type
)
returnsales_tax_rate.tax_rate%type
is
l_retsales_tax_rate.tax_rate%type;
begin
selecttax_rate
intol_ret
fromsales_tax_ratet,customersc
wherec.cust_id=p_cust_id
andt.state_code=c.state_code;
--simulatesometimeconsuming
--processingbysleepingfor1sec
dbms_lock.sleep
(1);
returnl_ret;
exception
whenNO_DATA_FOUNDthen
returnNULL;
whenothersthen
raise;
end;
/
执行几次函数,如下所示。
记住要启用计时来记录每次执行使用的时间。
SQL>selectget_tax_rate
(1)fromdual;
GET_TAX_RATE
(1)
---------------
6
1rowselected.
Elapsed:
00:
00:
01.23
SQL>selectget_tax_rate
(1)fromdual;
GET_TAX_RATE
(1)
---------------
6
1rowselected.
Elapsed:
00:
00:
01.17
每次执行使用的时间几乎都相同。
(我特意使用了休眠语句来延迟函数内的处理;否则返回速度太快。
)如果您仔细分析代码,将注意到每次调用函数时,几乎都会返回相同的值。
客户不经常更改所在的州,并且州的税率也很少变化,因此对于同一个客户,每次执行的税率几乎完全相同。
当且仅当州税率更改或客户搬离该州时,税率才会变化。
因此,缓存这一函数的结果会怎么样呢?
Oracle数据库11g 可让您完成这一任务。
您也可以使用result_cache子句实现对函数结果的缓存。
但当州实际上更改了税率或客户搬离州时,又该如何呢?
这一特性让您可以指定对底层表的依赖,因此那些表中的数据更改将触发失效操作,并随后重建函数中的缓存。
以下是添加了结果缓存代码的同一函数(粗体):
createorreplacefunctionget_tax_rate
(
p_cust_idcustomers.cust_id%type
)
returnsales_tax_rate.tax_rate%type
result_cache
relies_on(sales_tax_rate,customers)
is
l_retsales_tax_rate.tax_rate%type;
begin
selecttax_rate
intol_ret
fromsales_tax_ratet,customersc
wherec.cust_id=p_cust_id
andt.state_code=c.state_code;
--simulatesometimeconsuming
--processingbysleepingfor1sec
dbms_lock.sleep
(1);
returnl_ret;
exception
whenNO_DATA_FOUNDthen
returnNULL;
whenothersthen
raise;
end;
/
更改后,以同一方式创建和执行函数:
SQL>selectget_tax_rate
(1)fromdual;
GET_TAX_RATE
(1)
---------------
6
1rowselected.
Elapsed:
00:
00:
01.21
需要1.21秒,与上次使用非缓存方式一样,但我们来看一下随后的执行:
SQL>selectget_tax_rate
(1)fromdual;
GET_TAX_RATE
(1)
---------------
6
1rowselected.
Elapsed:
00:
00:
00.01
使用的时间只有0.01秒!
到底是怎么回事?
函数执行第一次时,耗时1.21秒。
但这一次的重要区别是它在执行时缓存了结果。
后续的调用不执行该函数,只从缓存中获取结果。
因此,它没有休眠函数代码中指定的1秒钟。
缓存只针对customer_id1。
如果针对另一个客户执行函数,又会如何?
SQL>selectget_tax_rate(&n)fromdual;
Entervalueforn:
5
old1:
selectget_tax_rate(&n)fromdual
new1:
selec
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java 缓存 数据