我有一张带有列的表格' A'和' B'。
' A'是一列90%' null'和10%不同的值,大多数时候我查询记录这些不同的值中的一个或两个。
和' B'是一个90%值=' 1'和10%不同的值,大部分时间我都会查询这些不同值中的一个或两个。
在此表中,我们大多数时间都有DML事务。
现在,我不知道这些列上的定义索引是好的吗?如果是哪种索引?
答案 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 NULL
或WHERE 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)
假设您创建了一个名为_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上的索引也无济于事
Q3: select * from MyTable where B = 1;
但它有助于使用不同的值
Q4: select * from MyTable where B = '456';
到目前为止,我回答说任何索引都无法帮助NULL值。因此,如果您需要在大多数时间查询Q1,我建议以下想法
确保您的DBMS版本支持将值包含在索引中。例如,Oracle 11g可以使用,但之前没有版本。
计划再次使用Oracle创建基于函数的索引here。但你至少可以接受这个想法。
重新设计应用程序的逻辑/您需要查询Null值。我更喜欢这种方法。