在他的回答中,文森特说:
“两个查询都可以使用 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”,其余的都是高度选择性的,那么索引可能有用也可能没有用。我们在收集索引时可能需要生成直方图,但只有在查询使用文字而不是绑定变量时它们才真正有用。