0

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

SELECT COUNT (1) FROM tax_proposal_dtl WHERE tax_proposal_no = :b1 AND taxid != :b2 AND INSTR(:b3 , ',' || STATUS || ',' ) > 0 ;

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

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

正如 Jon 所建议的那样,在对该主题进行了进一步研究之后(特别是关于 _SMALL_TABLE_THRESHOLD),我正在添加更多细节。

当前版本:Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit

第二个数据库的详细信息:

带有 _STT 的第二个 DB 的内存详细信息

来自 DBA_SEGMENTS 的表的总块数 = 196736

第一个数据库的详细信息:

带有 _STT 的第一个 DB 的内存详细信息

来自 DBA_SEGMENTS 的表的总块数 = 172288

两个数据库的执行计划相同,但有两个主要区别:a)第二个数据库缓存选项在表上为假(我尝试了更改表缓存但仍然对性能没有影响)

b) 在第 2 个 DB 上,因为 _STT 参数为 23920,因此根据 5*_STT 规则表将不被视为中型表,而在第 1 个 DB 上,_STT 参数为 48496,因此根据 5*_STT 规则表将被视为中型表。

下面是基于我迄今为止对 _STT 的研究的图表,它是一个 Cache 参数,用于说明系统在不同表大小下的行为方式。

描述表大小、缓存和 _STT 参数影响的图表

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

根据此链接,我已在第二个 DB 的会话中设置 _STT 参数

alter session set "_small_table_threshold"=300000;

因此,性能得到了显着提高,几乎与第一个 0 磁盘读取的 DB 相同,因为这意味着表将被认为是小型的。

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

https://jonathanlewis.wordpress.com/2011/03/24/small-tables/

https://hoopercharles.wordpress.com/2010/06/17/_small_table_threshold-parameter-and-buffer-cache-what-is-wrong-with-this-quote/?unapproved=43522&moderation-hash=be8d35c5530411ff0ca96388a6fa8099#comment-43522

https://dioncho.wordpress.com/tag/full-table-scan/

https://mikesmithers.wordpress.com/2016/06/23/oracle-pinning-table-data-in-the-buffer-cache/

http://afatkulin.blogspot.com/2012/07/serial-direct-path-reads-in-11gr2-and.html

http://afatkulin.blogspot.com/2009/01/11g-adaptive-direct-path-reads-what-is.html

4

1 回答 1

1

关键字CACHENOCACHE有点误导 - 它们不只是启用或禁用缓存,它们只是通过更改数据在缓存中的存储方式来或多或少地进行缓存读取。与大多数内存系统一样,Oracle 缓冲区高速缓存不断添加新数据并老化旧数据。默认情况下,NOCACHE仍然会将来自全表扫描的表数据添加到缓冲区缓存中,但会将其标记为第一个过期的数据。

根据SQL 语言参考:

缓存

对于频繁访问的数据,该子句表示在执行全表扫描时,为该表检索的块放置在缓冲区缓存中最近最少使用 (LRU) 列表的最近使用端。此属性对于小型查找表很有用。

...

诺卡奇

对于不经常访问的数据,该子句表示在执行全表扫描时,将为此表检索到的块放置在缓冲区缓存中 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;
/
于 2020-06-09T02:00:04.173 回答