选择未编制索引的列时,将忽略复合索引(Oracle)

时间:2015-11-09 21:52:02

标签: sql oracle join composite-index full-table-scan

我们有一个简单的 join 语句,其中一些 when 子句可能变为为空。该语句由应用程序生成。 当我们有为null 约束时,会出现查询计划的问题。
我们遵循StackExchange文章中描述的方法,并为列创建了一个复合索引 - 可空和我们加入的列。仅当我们仅选择索引列时,它才有用。如果我们选择未编制索引的列,则会忽略它,而查询结果是相同的 - 例如,没有选择任何行。

我们看到的唯一选择 - 更改应用程序的逻辑,但可能还有一种方法可以在db级别上解决这个问题吗?

--Illustrative sample. Prepare tables and indexes:
create table tableA 
 (
  Acol1 varchar2(32) NOT NULL,
  Acol2 varchar2(32),
  Acol3 varchar2(32)
 );
insert into tableA (Acol1, Acol2, Acol3)
            values ('abcd1','abcd2A','abcd3A'); 

create table tableB 
 (
  Bcol1 varchar2(32) NOT NULL, 
  Bcol2 varchar2 (32),
  Bcol3 varchar2 (32)
 ); 
insert into tableB (Bcol1, Bcol2, Bcol3) 
values             ('abcd1','abcd2B','abcd3B'); 

create index tableA_col12 on tableA (acol1, acol2); 
create index tableB_col1 on tableB (Bcol1); 
commit;

然后我们检查计划:

1

 select a.Acol1 from tableA a join tableB b on a.Acol1 = b.Bcol1 where Acol2 is null; 
 --no rows selected

Plan1 - 范围扫描

2

 select * from tableA a join tableB b on a.Acol1 = b.Bcol1 where Acol2 is null;
--no rows selected

Plan2 (上面的相同链接) - 全表扫描

提高绩效的最佳方法是:更改查询,使用更智能的索引或应用固定计划?

*更新*在我准备这个问题时,我的样本计划自行更改,现在我们有Plan2*而不是Plan2 - 没有全表扫描。但是,如果我重新创建样本(删除表并再次准备它们) - 计划再次是Plan2(全表扫描)。这个技巧在实际的DB中不会发生。

1 个答案:

答案 0 :(得分:0)

我的评论有点轻率,所以我会尝试给你一些更详细的信息。以下是一些有关优化SQL系统和特定查询的一般提示

  • 首先,@ GordonLinoff是正确的(一如既往)你不会从小桌子上得到任何有意义的东西。优化器知道并将以不同的方式工作。

  • 在您拥有一个合适大小的表(至少50k行,具体取决于您的内存)后,您需要确保对您的表运行统计信息或优化器(和索引)不起作用

  • 第三,您需要使用这些工具,学习如何理解执行计划 - 如果不深入了解系统告诉您的内容,您就无法更好地掌握这些技术。现代SQL数据库有一些工具可以查看查询并建议索引 - 使用它们,就像您可以学到很多的执行计划一样。请记住,这些工具并非万无一失,您需要尝试建议并查看它们是否有效。

  • 最后,请阅读很多内容。我认为特别有趣的一个来源是stackoverflow用户Quassnoi谁拥有explainextended的博客。虽然最近没有那么活跃这个博客(以及他的许多答案)非常有启发性,但我希望你会喜欢它们。有很多关于这个主题的博客和书籍,每一点都有帮助。

在这种情况下,对于你的大桌子,我认为(这有一点需要注意,你的数据库和数据模型有很多我不知道的事情)只需在索引中添加更多列就可以了 - 但是使用Oracle工具,看看它的建议。先尝试一下。