oracle 两个数据库中的同一查询使用不同的索引

0md85ypi  于 2023-06-22  发布在  Oracle
关注(0)|答案(2)|浏览(172)

我有下面的查询,当我在两个不同的数据库中使用不同的数据运行查询时,解释计划似乎不同。

SELECT *
      FROM   voucher_row_tab g,
             voucher_type_tab v
      WHERE  g.company            = '12'
      AND    (g.voucher_date BETWEEN to_date('2022-12-10', 'YYYY-MM-DD')  AND ('2023-12-10', 'YYYY-MM-DD'))
      AND    (g.account      BETWEEN  '100'    AND '200')
      AND    g.company            = v.company
      AND    g.voucher_type       = v.voucher_type  
      AND    v.simulation_voucher  != 'TRUE'
      AND    'TRUE' = (SELECT TEST_API.CHECK (g.company, g.pc_id) FROM DUAL);

我将这两个数据库称为A和B。
当我检查A中的解释计划时,它使用在<COMPANY,ACCOUNTING_PERIOD,ACCOUNTING_YEAR,VOUCHER_TYPE>列上定义的索引,B使用在<PC_ID,COMPANY,ACCOUNTING_YEAR>列上定义的索引。这两个数据库都定义了索引,但是在执行相同的查询时,数据库的行为不同。
有人知道为什么会这样吗?表中的数据是否对此有任何影响?

iyfamqjs

iyfamqjs1#

是的,数据库中存在的不同数据会影响索引的使用。
对于具有 * 基于成本的 * 查询优化器的数据库,这正是期望的行为,因为使用索引不一定是在所有情况下计算查询的最佳(=最快)选择。
这种情况的一个例子是,当表本身相当小,并且阅读整个表比首先读取索引,找到要读取的表的哪一部分,然后只读取表更快。
足够深入地解释细节超出了这个答案的范围-Oracle数据库文档对这个广泛的主题有相当好的介绍。
开始理解不同执行计划的一个好地方是查看两个数据库上的EXPLAIN PLAN输出,并比较每个步骤的预期行/成本。

ghhkc1vu

ghhkc1vu2#

Oracle的基于成本的优化器(CBO)基于各种统计数据(段、系统、(近)实时、动态采样等)进行复杂的计算,考虑行数、不同值计数、分布、块计数、高值和低值、直方图等。并试图预测潜在的数千种不同计划排列的时间成本,然后选择它认为成本最低的计划。这意味着计划是不稳定的-随着数据的变化和环境以各种方式转变,计划在没有警告的情况下发生变化。您可以锁定它们,但通常它们可以随着数据的变化和Oracle对该数据的了解(统计数据)而自由移动。这是一个试图变得智能和自适应的程序的副作用。
因此,您永远不应该假设或期望在两个不同的数据库中执行相同的计划,甚至在同一个数据库中执行相同的计划。然而,由于涉及的复杂性,Oracle(或任何其他RDBMS)经常犯错误,其计算的成本是错误的,在这种情况下,计划将是错误的。这是很常见的事。对于大多数SQL,这种差异是无法检测到的,我们不必担心它。但有时错误会导致非常糟糕的执行计划,导致我们错过SLA,这需要我们的注意。
如果您希望强制执行某些计划步骤,那么可以利用提示来限制优化器的选择集。虽然提示是不可移植的,并且在开发社区中经常被劝阻,但是当计划可变性威胁到我们的SLA时,它们在稳定计划方面做得非常好。但它们应该只由一个对自己所做的事情有很好理解的知识人员使用,否则它们可能会对你不利。这是一个复杂的问题,不幸的是,这里无法涵盖。对于无法使用提示或没有足够的知识来正确使用提示的情况,您可以做的最好的事情是确保查询中涉及的每个对象(表和索引)都具有良好的非陈旧统计信息。这将至少解决一部分问题,尽管不是全部。

相关问题