我有下面的查询,当我在两个不同的数据库中使用不同的数据运行查询时,解释计划似乎不同。
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>列上定义的索引。这两个数据库都定义了索引,但是在执行相同的查询时,数据库的行为不同。
有人知道为什么会这样吗?表中的数据是否对此有任何影响?
2条答案
按热度按时间iyfamqjs1#
是的,数据库中存在的不同数据会影响索引的使用。
对于具有 * 基于成本的 * 查询优化器的数据库,这正是期望的行为,因为使用索引不一定是在所有情况下计算查询的最佳(=最快)选择。
这种情况的一个例子是,当表本身相当小,并且阅读整个表比首先读取索引,找到要读取的表的哪一部分,然后只读取表更快。
足够深入地解释细节超出了这个答案的范围-Oracle数据库文档对这个广泛的主题有相当好的介绍。
开始理解不同执行计划的一个好地方是查看两个数据库上的EXPLAIN PLAN输出,并比较每个步骤的预期行/成本。
ghhkc1vu2#
Oracle的基于成本的优化器(CBO)基于各种统计数据(段、系统、(近)实时、动态采样等)进行复杂的计算,考虑行数、不同值计数、分布、块计数、高值和低值、直方图等。并试图预测潜在的数千种不同计划排列的时间成本,然后选择它认为成本最低的计划。这意味着计划是不稳定的-随着数据的变化和环境以各种方式转变,计划在没有警告的情况下发生变化。您可以锁定它们,但通常它们可以随着数据的变化和Oracle对该数据的了解(统计数据)而自由移动。这是一个试图变得智能和自适应的程序的副作用。
因此,您永远不应该假设或期望在两个不同的数据库中执行相同的计划,甚至在同一个数据库中执行相同的计划。然而,由于涉及的复杂性,Oracle(或任何其他RDBMS)经常犯错误,其计算的成本是错误的,在这种情况下,计划将是错误的。这是很常见的事。对于大多数SQL,这种差异是无法检测到的,我们不必担心它。但有时错误会导致非常糟糕的执行计划,导致我们错过SLA,这需要我们的注意。
如果您希望强制执行某些计划步骤,那么可以利用提示来限制优化器的选择集。虽然提示是不可移植的,并且在开发社区中经常被劝阻,但是当计划可变性威胁到我们的SLA时,它们在稳定计划方面做得非常好。但它们应该只由一个对自己所做的事情有很好理解的知识人员使用,否则它们可能会对你不利。这是一个复杂的问题,不幸的是,这里无法涵盖。对于无法使用提示或没有足够的知识来正确使用提示的情况,您可以做的最好的事情是确保查询中涉及的每个对象(表和索引)都具有良好的非陈旧统计信息。这将至少解决一部分问题,尽管不是全部。