我们有一个简单的 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中不会发生。
答案 0 :(得分:0)
我的评论有点轻率,所以我会尝试给你一些更详细的信息。以下是一些有关优化SQL系统和特定查询的一般提示
首先,@ GordonLinoff是正确的(一如既往)你不会从小桌子上得到任何有意义的东西。优化器知道并将以不同的方式工作。
在您拥有一个合适大小的表(至少50k行,具体取决于您的内存)后,您需要确保对您的表运行统计信息或优化器(和索引)不起作用
第三,您需要使用这些工具,学习如何理解执行计划 - 如果不深入了解系统告诉您的内容,您就无法更好地掌握这些技术。现代SQL数据库有一些工具可以查看查询并建议索引 - 使用它们,就像您可以学到很多的执行计划一样。请记住,这些工具并非万无一失,您需要尝试建议并查看它们是否有效。
最后,请阅读很多内容。我认为特别有趣的一个来源是stackoverflow用户Quassnoi谁拥有explainextended的博客。虽然最近没有那么活跃这个博客(以及他的许多答案)非常有启发性,但我希望你会喜欢它们。有很多关于这个主题的博客和书籍,每一点都有帮助。
在这种情况下,对于你的大桌子,我认为(这有一点需要注意,你的数据库和数据模型有很多我不知道的事情)只需在索引中添加更多列就可以了 - 但是使用Oracle工具,看看它的建议。先尝试一下。