使用静态查询方式存在问题;在使用 CURSOR_SHARING=FORCE 选项时也要非常小心——如果您没有进行覆盖测试以确保您的所有其他查询都能按照您想要的方式工作,它真的会让您的系统陷入困境。
静态查询的问题:
(x is null or x = col) 谓词往往会扼杀任何使用索引的机会。由于查询计划是在第一次解析查询时计算的,因此您使用的索引将基于第一次运行查询的值;稍后的运行可能不会限制在相同的列上,但仍将使用相同的索引。
拥有一个带有替换变量的静态语句将阻止优化器根据数据分布对要使用的索引做出明智的选择。在动态查询中(或在第一次运行带有绑定变量的查询时),Oracle 将看到您的约束的选择性;高度选择性的约束将成为索引使用的主要候选者。例如,如果您的表为美国的每个人都有一行,则 STATE='Alaska' 将更有可能使用 STATE 上的索引而不是 STATE='California'。
当然,在这两种情况下,如果您的 WHERE 子句中的动态列无论如何都没有被索引,那没关系,尽管如果在您正在谈论的大小的数据库中出现这种情况,我会感到惊讶。
此外,请考虑所有这些硬解析的实际成本。是的,硬解析序列化系统资源,这使得它们变得昂贵,但仅限于大量查询的上下文中。就其性质而言,即席查询不会经常运行。您为一整天内发生的所有硬解析所支付的成本可能比使用错误索引的单个查询的成本低数百倍。
过去,我实现这些系统的方式与您在此处所做的非常相似——基本查询部分,然后迭代约束列表并添加 WHERE 子句谓词。我不认为有人很难维护或理解,尤其是当您谈论不涉及向 FROM 子句添加大量子查询或额外表的约束时。
需要考虑的一件事:如果该系统主要是离线系统(换句话说,不是不断更新或插入 - 由定期加载的批量数据填充),您可能需要考虑使用 BITMAP 索引。位图索引与常规 b-tree 索引的不同之处在于,可以同时使用单个表上的多个索引,并且位图索引在磁盘上比 b-tree 小得多。它们非常适用于这样的应用程序 - 您将有各种无法在设计时定义的约束。您只想将位图索引放在具有相对较少不同值的列上 - 例如,一个值构成不少于表的 1/1000 - 所以不要在唯一列上使用位图。
However, the downside is that bitmap indexes will noticeably degrade the performance of inserts and updates. The best practice for bitmaps is to use them in data warehouse applications, and they are dropped prior to loads and recreated afterwards.