如果我有一个表TABLE_1
,我们说5列:
COL1 | COL2 | COL3 | COL4 | COL5
[line]
[line]
[...]
我想做两个主要查询:
SELECT * FROM table_a WHERE COL1 = 'X' and COL2 = 'Y'
另一个是:
SELECT * FROM table_a WHERE COL2 = 'Z'
我应该创建哪些索引?创建一个列COL1
和COL2
将索引两个查询,或者我是否需要另一个索引仅为COL2
,以便有第二个查询更快?
谢谢!
两个查询都可以使用table_a(COL2, COL1)
上的常规b树索引。
单独在COL2
上使用一个索引可能会更有效,但是额外的索引会占用空间,并且会减慢插入(如果要更新该列的话)的速度。这是一种权衡。
文森特在回答中是这样说的:
" table_a(COL2, COL1)上的常规b树索引可以被两者使用查询。"
那句话的关键字是"可能"。因为这样的索引也可能不会被任何一个查询使用。
数据库索引是一个复杂而微妙的问题。有很多关于这个话题的书。理查德·富特(Richard Foote)的博客一直在谈论Oracle索引(和David Bowie),这已经有好几年了。
如果不知道这个表的一些基本事实,我们就不能给出一个明确的答案:它有多少行?COL1有多少不同的值?COL2有多少不同的值?
那么,让我们看看其他的答案。
如果TABLEA只包含十几行,那么全表扫描将比任何索引读取更有效。
如果COL2是唯一的,我们只需要索引table_a(COL2)
如果COL2是非选择性的(与总行数相比相对较少的值),则第二个查询应该使用全表扫描而不是索引读取。
如果COL2是非选择性的,但COL1是高度选择性的(与总行数相比有很多值,但不是唯一的),那么第一个查询应该在table_a(COL2, COL1)
上使用索引。
如果COL2不是特别有选择性,COL1也不是特别有选择性,但两者的组合是高度有选择性的,那么第一个查询应该在table_a(COL2, COL1)
上使用索引。全表扫描将是第二个查询的首选路径。
如果COL1是唯一的,它应该有一个索引,这是在第一个查询中使用的,但在第二个查询中显然没有帮助。
然后是null的问题,这使问题进一步复杂化。null不被索引,除了复合索引(和某些其他特殊情况)。
一个真正完整的答案也会解决倾斜的问题:如果COL1中90%的行是'0',其余的是高度选择性的,那么索引可能有用,也可能没用。当我们收集索引时,我们可能需要生成直方图,但是它们只有在查询使用字面量而不是绑定变量时才真正有用。
可以考虑在col2和col1上使用复合索引。有关更多细节,请参阅Oracle概念指南