null 在性能调优中的作用
Posted
技术标签:
【中文标题】null 在性能调优中的作用【英文标题】:Role of null in performance tuning 【发布时间】:2019-07-24 16:44:39 【问题描述】:此查询与查询的性能调整有关。 我有一个表 TEST1,它有 200,000 行。 表结构如下。
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
我还有一张表 STATUS,
ACCOUNT_NUMBER VARCHAR2(16)
STATUS VARCHAR2(2)
ACCOUNT_NUMBER IDX_STATUS_ACCT UNIQUE
当我编写一个连接到如下表的查询时,执行时间太长而且查询成本很高。
SELECT ACCOUNT_NUMBER,STATUS
FROM TEST,STATUS
where TEST.ACCOUNT_NUMBER = STATUS.ACCOUNT_NUMBER
AND TEST.BRANCH = '1000';
产品团队有查询返回以获取与 ||null 相同的详细信息 在 where 条件下,查询返回相同的结果,但 与我的查询相比,性能非常好。
SELECT ACCOUNT_NUMBER,STATUS
FROM TEST,STATUS
where TEST.ACCOUNT_NUMBER = STATUS.ACCOUNT_NUMBER
AND TEST.BRANCH||NULL = '1000';
谁能解释一下 ||null
在 where 条件下是如何产生这种差异的。
我写这篇文章是因为,我想知道它是如何产生影响的,并且想尽可能地使用它。
【问题讨论】:
学习使用现代、明确、标准JOIN
语法。
您可以检查查询计划以查找差异。也许“null”正在强制使用索引。在 sqlplus 中尝试 EXPLAIN PLAN FOR ACCOUNT_NUMBER
is present in SELECT
子句没有任何别名,并且出现在两个表中
了解如何在 DBMS 中使用性能分析工具。甚至 EXPLAIN 也会告诉你很多(一旦你修复了明显的错误)。第二个查询将忽略包含“BRANCH”的索引。根据数据分布和索引类型,它可能对第一个查询使用跳过扫描。对 TEST 运行全表扫描可能比索引查找更快。检查您的统计数据。
【参考方案1】:
如果您打开自动跟踪并获取两个查询的执行计划,我猜您的查询正在尝试使用索引IDX_TEST_SCHM_BR
而另一个查询由于子句TEST.BRANCH||NULL
而无法使用索引并且无法使用索引,因为该子句阻止优化器使用索引。
通常,在表列上使用函数会阻止 Oracle 使用索引,在您的情况下,使用 ||
运算符将空值附加到表列就像调用函数 concat(TEST.BRANCH||NULL)
。为了让您的查询运行得更快,您可以
-
添加忽略索引
SELECT /*+ NOINDEX(TEST1 IDX_TEST_SCHM_BR */ ACCOUNT_NUMBER, ...
的提示(不推荐)
创建一个以BRANCH
作为唯一列的新索引(推荐)
正如@symcbean 所指出的,如果索引不是很有选择性(即:查询返回表中的很多行),那么全表扫描可能会更快。在这种情况下,由于BRANCH
列不是索引中的第一列,Oracle 必须跳过索引来查找与连接条件匹配的行。 一般 经验法则是,如果查询返回的行数超过大约 20%,则全表扫描会更快。在这种情况下,由于索引定义,Oracle 必须读取多个索引条目,一直跳过直到找到下一个新的BRANCH
值,所以在这种情况下,可能远低于 5%
还要确保您的表收集了当前的统计信息,如果您的任何列不为空,您应该在表定义中指定以帮助 Oracle 优化器避免像您遇到的问题。
【讨论】:
horse_w_null_name:注意我把 general 和 around 放在我的“经验法则”中——另一个经验法则:总是针对 您的数据。以上是关于null 在性能调优中的作用的主要内容,如果未能解决你的问题,请参考以下文章