oracle 12c中缓存和nocache的全表扫描行为

oracle 12c中缓存和nocache的全表扫描行为,oracle,caching,oracle12c,full-table-scan,Oracle,Caching,Oracle12c,Full Table Scan,我有一个相同的查询运行在两个不同的数据库服务器上,配置几乎相同。查询正在对一个表执行完整表扫描(FTS) 从税收方案dtl中选择计数(1),其中税收方案编号=:b1和税收!=:b2和INSTR(:b3','| | | |',')>0 在第一个DB上,我在不到3秒的时间内得到结果,磁盘读取为0,而在第二个DB上,磁盘读取为高,经过的时间约为9秒 两个DBs上的表配置之间的唯一区别是,第一个表上的缓存为'Y',而第二个表上的缓存为'N'。据我所知,在FTS的情况下,将不使用缓存,而是使用直接路径读取

我有一个相同的查询运行在两个不同的数据库服务器上,配置几乎相同。查询正在对一个表执行完整表扫描(FTS)

从税收方案dtl中选择计数(1),其中税收方案编号=:b1和税收!=:b2和INSTR(:b3','| | | |',')>0

在第一个DB上,我在不到3秒的时间内得到结果,磁盘读取为0,而在第二个DB上,磁盘读取为高,经过的时间约为9秒

两个DBs上的表配置之间的唯一区别是,第一个表上的缓存为'Y',而第二个表上的缓存为'N'。据我所知,在FTS的情况下,将不使用缓存,而是使用直接路径读取。那么,为什么同一查询的性能会受到cache/nocache的影响(因为这是两个env之间的唯一区别,甚至执行计划也是相同的)

正如Jon所建议的,在对这个主题做了进一步的研究之后(特别是关于_SMALL_TABLE_THRESHOLD),我将添加更多细节

当前版本:Oracle数据库12c企业版12.2.0.1.0-64位

第二数据库的详细信息:

来自DBA_段的表的总块计数=196736

第一数据库的详细信息:

来自DBA_段的表的总块计数=172288

两个DBs的执行计划相同,但有两个主要区别: a) 表上的On 2nd DB cache选项为false(我尝试更改表缓存,但仍然对性能没有影响)

b) 在第二个DB上,因为_STT参数为23920,所以根据5*_STT规则,表将不被限定为中等大小的表,而在第一个DB上,因为_STT参数为48496,所以根据5*_sttrue,表将被限定为中等大小的表

下面是一个基于我目前研究的图表,它是一个缓存参数,表示系统在不同表大小下的行为

请让我知道我的理解是否正确,假设缓存选项对中型或大型表没有影响,但它将有助于在LRU中保留小型表更长的时间。因此,基于上述假设和图表,我得出结论,在第二个DB表的情况下,被归类为大型表,因此DPR和更多的运行时间,而在第一个DB表的情况下,被归类为中型表,因此缓存读取和更少的运行时间

根据这一点,我已经在第二个DB的会话上设置了_STT参数

alter session set "_small_table_threshold"=300000;
所以,性能有了很大的提高,几乎与第一个DB相同,磁盘读取为0,因为这意味着表的大小将被认为很小

我在研究中使用了以下文章


关键字
CACHE
NOCACHE
有点误导性-它们不只是启用或禁用缓存,它们只是通过更改数据在缓存中的存储方式来增加或减少缓存读取的可能性。与大多数内存系统一样,Oracle缓冲区缓存不断添加新数据,并老化旧数据。默认情况下,
NOCACHE
,仍会将完整表扫描中的表数据添加到缓冲区缓存,但它会将其标记为要过期的第一条数据

根据

缓存

对于经常访问的数据,本子句表示 为该表检索的块最多放置一次 最近使用缓冲区中最近使用最少(LRU)列表的末尾 执行完整表扫描时缓存。此属性非常有用 用于小型查找表

NOCACHE

对于未访问的数据 通常,此子句指示为此检索的块 表至少放在LRU列表中最近使用的末尾 执行完整表扫描时的缓冲区缓存。NOCACHE是最重要的 LOB存储的默认值

真正的行为可能要复杂得多。内存选项、结果缓存、OS和SAN缓存、直接路径读取(通常是为了并行)、小表阈值(如果超过阈值,Oracle不会缓存整个表)以及其他我想不到的功能可能会影响数据的缓存和读取方式


编辑:我不确定是否可以为您的分析添加更多内容。关于这些阈值和表扫描类型,没有很多官方文档。看来你和其他人一样了解这个问题

我要提醒的是,只有在极少数情况下才需要这种全表扫描优化。为什么查询经常对1GB表进行全表扫描?难道没有一个索引或物化视图可以提供帮助吗?或者,如果您需要与生产相匹配的开发环境,您可能只需要添加更多内存

另一个选项不是更改小表阈值,而是更改表的感知大小。修改统计信息,使Oracle认为表很小。这样就不会影响其他表

begin
    dbms_stats.set_table_stats(ownname => user, tabname => 'TAX_PROPOSAL_DTL', numblks => 999);
    dbms_stats.lock_table_stats(ownname => user, tabname => 'TAX_PROPOSAL_DTL');
end;
/

谢谢你,乔恩。但根据DBA,两个env上的一切都是一样的。所以我无法理解为什么第一个磁盘上的读取是0,而第二个磁盘上的读取是高的,最终经过的时间是高的。你知道我该如何检查这种差异以及可能的原因是什么吗?但是你不是说数据库之间的缓存设置不同吗?这种桌子的设置可以解释这种差异。缓存的一个困难是使用模式会影响性能。一个数据库可能正在运行从同一个表读取的其他查询,将其保留在缓存中,从而间接地改进您关心的查询。您可能能够在诸如
GV$ACTIVE\u SESSION\u HISTORY
之类的视图中跟踪相关查询,但这可能很困难。但根据我最近对FTS主题缓存的了解,它也依赖于“小表”阈值,因此如果大表中的块数大于“小表”阈值,则FTS将直接读取一个主题