定义稀疏列的索引

时间:2016-12-21 08:22:47

标签: oracle performance indexing sparse-matrix

我有一张带有列的表格' A'和' B'。

' A'是一列90%' null'和10%不同的值,大多数时候我查询记录这些不同的值中的一个或两个。

和' B'是一个90%值=' 1'和10%不同的值,大部分时间我都会查询这些不同值中的一个或两个。

在此表中,我们大多数时间都有DML事务。

现在,我不知道这些列上的定义索引是好的吗?如果是哪种索引?

3 个答案:

答案 0 :(得分:1)

原则上Bitmap Index在这种情况下会是最好的。但是,由于多用户环境它们不适合 - 您可能会因表锁而显着减慢应用程序速度,甚至可能会死锁。

也许您可以通过智能分区和Partial Indexes的使用来优化您的应用程序(Oracle 12c中的新功能)

下面的CREATE TABLE语句应该是等效的。

CREATE TABLE YOUR_TABLE (a INTEGER, b INTEGER, ... more COLUMNS)
PARTITION BY LIST (a) SUBPARTITION BY LIST (b) (
    PARTITION part_a_NULL VALUES (NULL) (
        SUBPARTITION part_a_NULL_b_1 VALUES (1) INDEXING OFF,
        SUBPARTITION part_a_NULL_b_other VALUES (DEFAULT) INDEXING ON
    ),
    PARTITION part_a_others VALUES (DEFAULT) (
        SUBPARTITION part_a_others_b_1 VALUES (1) INDEXING OFF,
        SUBPARTITION part_a_others_b_other VALUES (DEFAULT) INDEXING ON
    )   
);

CREATE TABLE YOUR_TABLE (a INTEGER, b INTEGER, ... more COLUMNS)
PARTITION BY LIST (a) SUBPARTITION BY LIST (b) 
    SUBPARTITION TEMPLATE (
        SUBPARTITION b_1 VALUES (1) INDEXING OFF,
        SUBPARTITION b_other VALUES (DEFAULT) INDEXING ON
    )
(
    PARTITION part_a_NULL VALUES (NULL),
    PARTITION part_a_others VALUES (DEFAULT)
);

CREATE INDEX IND_A ON YOUR_TABLE (A) LOCAL INDEXING PARTIAL;
CREATE INDEX IND_B ON YOUR_TABLE (B) LOCAL INDEXING PARTIAL;

通过此,您的索引将仅消耗整个表空间的10%。如果你的WHERE条件是WHERE A IS NULLWHERE B = 1,那么Oracle优化器无论如何都会跳过这些索引。

使用此查询验证

SELECT table_name, partition_name, subpartition_name, indexing
FROM USER_TAB_SUBPARTITIONS
WHERE table_name = 'YOUR_TABLE';

如果在所需的子分区上使用INDEXING。

<强>更新

我只是看到实际上这是一种矫枉过正,因为A列上的NULL值无论如何都不会创建任何索引条目。所以,它可以简化为

CREATE TABLE YOUR_TABLE (a INTEGER, b INTEGER, ... more COLUMNS)
PARTITION BY LIST (b) (
    PARTITION part_b_1 VALUES (1) INDEXING OFF,
    PARTITION part_b_other VALUES (DEFAULT) INDEXING ON
);

答案 1 :(得分:0)

例如,如果您在A,B(按此顺序)上有索引a_b_idx:

  • a) select ... from ...其中A = ... 将使用索引

  • b) select ... from ...其中B = ... 不会使用索引

另一方面,如果B上有索引b_a_idx,则A:

  • a) select ... from ...其中A = ... 不会使用索引

  • b) select ... from ...其中B = ... 将使用索引

如果Oracle不在第一列上过滤,则Oracle不能在索引中使用第二列,因为在常规情况下,索引是树状结构:column1-&gt; column2-&gt; column3-&gt; etc。

如果您执行a)等查询,则只需要在A列上或索引A,B上进行索引。

如果您执行b)等查询,则只需要在B列上或在B,A列上进行索引。

Oracle不会在索引中存储全空值,但如果B包含非空值,它可以为A存储空值。

有时将整个表读入内存并忽略索引会更有成效。如果可能的结果集很大并且它适用于所有记录,优化器可以执行此操作,因为索引到记录的转换成本比读取的简单记录要多。

有时,对于没有统计信息的表,它会错误地发生,因此您需要使用 alter table ... compute statistics 或oracle 11+的作业,这些作业可以在没有作业的情况下计算这样的统计数据。

大多数时候,另一个索引对于查询来说是好事,但对于更新/磁盘来说却是坏事。每个索引占用磁盘空间,每次更新记录都会对每个索引进行更新。因此,对于大量更新的表,拥有多个索引并不好,但对于经常查询的表,最好让索引涵盖所有常见情况。

对于大多数平面查询(没有连接/子查询/层次结构),只使用1个索引,因此为每个列创建索引通常只是浪费磁盘空间。您需要多列索引来优化A = ...和B = ...

的位置

对于索引类型,您可能需要简单的非唯一索引。

答案 2 :(得分:0)

  • A栏

假设您创建了一个名为_columnA_index_的索引。通常,RDBMS中的索引不包含NULL值,这意味着_columnA_index_中没有索引条目指向具有NULL值的记录。因此,以下查询

Q1: select * from MyTable where A is null;

将导致表扫描(或者DBMS选择在另一列上使用另一个索引,如果有的话)

但是,由于有10%的记录具有不同的值&#39;,例如_columnA_index_当然会有助于查询。

Q2: select * from MyTable where A = '123';

在上面的示例中,如果查询返回&lt; 1%的记录,_columnA_index_是有帮助的。根据查询的选择性,索引可以极大地提高性能。您可以创建适合A列数据类型的索引。

  • B栏

同样,B上的索引也无济于事

Q3: select * from MyTable where B = 1;

但它有助于使用不同的值

Q4: select * from MyTable where B = '456';
  • NULL值

到目前为止,我回答说任何索引都无法帮助NULL值。因此,如果您需要在大多数时间查询Q1,我建议以下想法

  • 确保您的DBMS版本支持将值包含在索引中。例如,Oracle 11g可以使用,但之前没有版本。

  • 计划再次使用Oracle创建基于函数的索引here。但你至少可以接受这个想法。

  • 重新设计应用程序的逻辑/您需要查询Null值。我更喜欢这种方法。