null 在性能调优中的作用

Role of null in performance tuning

此查询与查询的性能调整有关。 我有一个 table TEST1,它有 200,000 行。 table 结构如下。

ACCOUNT_NUMBER      VARCHAR2(16)
BRANCH              VARCHAR2(10)
ACCT_NAME           VARCHAR2(100)
BALANCE             NUMBER(20,5)
BANK_ID             VARCHAR2(10)
SCHM_CODE           VARCHAR2(10)
CUST_ID             VARCHAR2(10)

指标如下

fields              Index Name              Uniquness
ACCOUNT_NUMBER      IDX_TEST_ACCT           UNIQUE
SCHM_CODE,BRANCH    IDX_TEST_SCHM_BR        NONUNIQUE

我还有一个table状态,

ACCOUNT_NUMBER      VARCHAR2(16)
STATUS              VARCHAR2(2)
ACCOUNT_NUMBER      IDX_STATUS_ACCT         UNIQUE

当我写一个连接到 table table 的查询时,如下所示,执行时间太长且查询成本高昂。

SELECT ACCOUNT_NUMBER,STATUS
FROM TEST,STATUS
where TEST.ACCOUNT_NUMBER = STATUS.ACCOUNT_NUMBER
AND TEST.BRANCH = '1000';

产品团队查询 return 以获取相同的详细信息 ||null 在 where 条件下,查询 returning 相同的结果,但 与我的查询相比,性能非常好。

SELECT ACCOUNT_NUMBER,STATUS
FROM TEST,STATUS
where TEST.ACCOUNT_NUMBER = STATUS.ACCOUNT_NUMBER
AND <b>TEST.BRANCH||NULL</b> = '1000';

任何人都可以解释一下 ||null 在 where 条件下是如何造成这种差异的。

我写这篇文章是因为,我想知道它是如何产生影响的,并且想尽可能地使用它。

如果你打开自动跟踪并获得两个查询的执行计划,我猜你的查询正在尝试使用索引 IDX_TEST_SCHM_BR 而另一个查询由于子句 [= 而无法使用索引11=] 并且不能使用索引,因为该子句阻止优化器使用索引。

通常,在 table 列上使用函数会阻止 Oracle 使用索引,在您的情况下,使用 || 运算符将空值附加到 table 列就像调用函数 concat(TEST.BRANCH||NULL)。要使您的查询 运行 更快,您可以

  1. 添加忽略索引的提示SELECT /*+ NOINDEX(TEST1 IDX_TEST_SCHM_BR */ ACCOUNT_NUMBER, ...(不推荐)
  2. BRANCH 作为唯一列创建一个新索引(推荐)

正如@symcbean 指出的那样,如果索引不是很有选择性,(即:查询 returns 中 table 中的很多行),则进行完整的 table 扫描可能会更快。在这种情况下,由于 BRANCH 列不是索引中的第一列,Oracle 必须跳过索引以查找与连接条件匹配的行。 一般 的经验法则是,如果查询返回的行数超过 around 20%,则完整的 table 扫描会更快.在这种情况下,由于索引定义,Oracle 必须读取多个索引条目,一直跳过,直到找到下一个新的 BRANCH 值,因此在这种情况下,可能

不到 5%

还要确保您的 table 收集了当前的统计信息,如果您的任何列不为空,您应该在 table 定义中指定,以帮助 Oracle 优化器避免像您这样的问题有。