1

我正在开发一个 DWH 提供脚本,该脚本在 Oracle Exadata 服务器上处理约 40M 行。

我有以下表格:

CREATE TABLE P.ARCHIVED_ID
(
    ID_ARCHIVED  VARCHAR2(31 BYTE) NOT NULL, -- CONSTRAINT UNIQUE / PRIMARY KEY
    IS_DELETE    CHAR(1 BYTE)      DEFAULT null
);

CREATE TABLE P.DWH_tableX
(
    ID      VARCHAR2(31 BYTE) NOT NULL, -- CONSTRAINT UNIQUE / PRIMARY KEY
    FIELD1  VARCHAR2(31 BYTE),
    FIELD2  VARCHAR2(31 BYTE),
    FIELD3  CHAR(2 BYTE),
    FIELD4  CHAR(1 BYTE)
);

如您所见,我有一个IS_DELETE可以设置为Y(默认为 NULL)的标志。

这是我需要使用的标准查询:

SELECT 
    ID,
    FIELD1,
    FIELD2,
    FIELD3,
    FIELD4
FROM P.DWH_tableX A
WHERE EXISTS (
    SELECT 1 
    FROM P.ARCHIVED_ID B 
    WHERE 
        A.ID = B.ID_ARCHIVED 
        AND IS_DELETE = 'Y'
    );

问题,有没有比以下索引更好的方法来优化它?

CREATE BITMAP INDEX P.I_IS_DELETE 
    ON P.ARCHIVED_ID(IS_DELETE)
LOGGING
TABLESPACE TBS_P_01
NOPARALLEL;

还有几点:

  • P.ARCHIVED_ID如果没有WHERE IS_DELETE = 'Y'(或者只有在我在脚本开头更新此字段时),我将永远不会访问
  • 默认情况下,Oracle 不会NULL在索引中注册,所以我使用NULL而不是"N",允许我创建部分="Y"位图索引,尽可能保持它的小和有用。 错误的
  • 我使用EXISTS, 而不是INOracle 推荐的(使用索引的能力),
  • 部分IS_DELETE = 'Y'现在为 0%,但由于它是 DWH,预计只会增加(因为每天在数据源中创建新行,而旧行被物理删除,将它们设置IS_DELETE = 'Y'在 DWH 中)
  • WHERE EXISTS我的脚本中使用了大约 20 次,因为这是我们处理冻结存档值的方式(将它们移动并返回到临时表上,并带有insert append提示)
4

3 回答 3

1

在任何性能调整练习中,细节都是魔鬼。以下是基于经验法则的一些猜测。您必须使用您的实际表和实际数据为自己运行一些性能基准测试。

“有没有比以下索引更好的方法来优化它”

几乎可以肯定,是的。

位图索引的好处在于拥有多个索引。这样,当我们对这些列发出查询过滤时,优化器可以选择执行星形转换来查找位图交集中的行。即便如此,二价列上的位图索引与具有多个不同值的列一样有用。

一个位图索引,特别是一个只有两个值的索引,并没有多大用处。鉴于维护位图索引的巨大开销及其并发问题,您可能应该考虑其他选项。

“Oracle Exadata 服务器上约 40M 行”

Oracle 设计了 ​​Exadata 设备来处理大量数据。这意味着寻找支持散列连接、布隆过滤器和类似操作的路径。对于 Exadata,一种常见的调优技术是删除现有索引而不是创建新索引。虽然比位图便宜,但 B-Tree 索引仍会产生资源(CPU、存储、内存)成本,因此值得考虑使用 Exadata 的蛮力是否能提供更低的总体成本。这就是我们付出高昂代价的原因。

但是,即使 Exadata 的原始能力也是有限的资源。因此,如果您要多次运行此查询(或者更确切地说是 EXISTS 子查询),您可能会从对排除的行进行聚类中受益。从您的问题来看,它似乎IS_DELETE是一个更新的属性,您不能在表级别使用物理组织(CTAS,属性聚类)。因此,B 树索引ARCHIVED_ID(IS_DELETE, ID_ARCHIVED)是主要候选者。

对于复合索引,通常最好从选择性最低的列开始,这里也是如此。您只对 where 的行感兴趣IS_DELETE = 'Y',因此以该列开头将减少子查询需要访问的块数。领先ID_ARCHIVED意味着子查询必须扫描整个索引。即使使用 Exadata,我们也应始终寻求最大限度地减少为获取一组记录而进行的工作。

但请对这个或任何其他指数进行基准测试。


“对于位图索引,我认为它只跟踪 Not Null 值(所以 Y),我弄错了吗?”

'如此害怕。位图索引对每个索引字段都有一个条目。因此,与单列 B 树索引不同,它们对条目 进行索引。null

“我使用 EXISTS,而不是 IN,正如 Oracle 推荐的(使用索引的能力),”

嗯,不知道你认为你在那里引用了什么 Oracle 建议。哪个更好取决于数据。但基本上如果子查询很大而主查询相对较小,那么 EXISTS 效率更高。但是如果数据量倒过来,主查询大,子查询小IN是更好的选择。鉴于您当前的起始位置是子查询不返回任何行(因为没有删除任何内容),并且在不久的将来可能会删除相对较少的记录,因此 IN 似乎更有可能是您应该使用的构造。

但同样:对每种方法进行基准测试,看看哪种方法更适合您的数据。

于 2017-04-30T07:58:19.453 回答
0

我的想法:1)为任何你想测试的东西做一个解释计划 2)因为 IS_DELETE 是 NULLABLE 不确定索引是否会被使用,如果不使用基于函数的索引,如果是,请查看解释计划

我会测试一个 FBI 的复合索引,比如

在 ARCHIVED_ID( decode(IS_DELETE,null,'N','Y'),ARCHIVED_ID)) 上创建索引 P.I_IS_DELETE;

收集统计数据

exec dbms_stats.gather_table_stats(用户,'ARCHIVED_ID',级联=>真);

相应地改变选择

从 P.DWH_tableX 中选择 ID、FIELD1、FIELD2、FIELD3、FIELD4 A WHERE 存在(从 P.ARCHIVED_ID B 中选择 1,其中 A.ID = B.ID_ARCHIVED 和解码(IS_DELETE,null,'N','Y')=' Y');

看看情况如何...

于 2017-04-30T08:04:57.163 回答
0

对于此查询:

SELECT ID, FIELD1, FIELD2, FIELD3, FIELD4
FROM P.DWH_tableX A
WHERE EXISTS (
    SELECT 1 
    FROM P.ARCHIVED_ID B 
    WHERE 
        A.ID = B.ID_ARCHIVED AND
        B.IS_DELETE = 'Y'
    );

我首先想到的索引是ARCHIVED_ID(ID_ARCHIVED, IS_DELETE). 知道位图索引是否表现更好会很有趣。

于 2017-04-30T00:11:46.990 回答