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 或使用 pl/sql developer 的解释计划窗口。 我怀疑 null 正在使用索引(跳过扫描)停止它,并在此过程中更改驱动表。获取两个查询的执行计划并进行比较。如果在这么少的记录上性能差异很大,您可能需要检查您的统计信息是否是最新的。不过,没有一个通用的“添加空”模式可以“在任何可能的地方”使用。 我怀疑您的查询一定没有给出答案。相反,它一定会给您错误 --- ORA-00918: column ambiguously defined as 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:注意我把 generalaround 放在我的“经验法则”中——另一个经验法则:总是针对 您的数据。

以上是关于null 在性能调优中的作用的主要内容,如果未能解决你的问题,请参考以下文章

Linux性能调优中内存调优工具的一些笔记整理

性能调优之三十六计 —— 「优中取优」字符串拼接 篇

性能调优之三十六计 —— 「优中取优」字符串拼接 篇

sqlserver性能调优中的逻辑读,物理读,预读是什么意思

关于Linux性能调优中磁盘IO调优的一些笔记

关于Linux性能调优中磁盘IO调优的一些笔记