默认情况下,查询提示用于指导查询优化器不产生合理的查询计划。首先,查询优化器的小背景:
数据库编程与几乎所有其他软件开发不同,因为它有一个机械组件。与 CPU 相比,磁盘寻道和旋转延迟(等待特定扇区到达磁盘磁头下方)非常昂贵。不同的查询解析策略将导致不同数量的 I/O,通常是完全不同的数量。判断正确或错误会对查询的性能产生重大影响。有关查询优化的概述,请参阅本文。
SQL 是声明性的——您指定查询的逻辑并让 DBMS 弄清楚如何解决它。现代的基于成本的查询优化器(某些系统,例如 Oracle 还保留了旧的查询优化器以实现向后兼容性)将对查询运行一系列转换。它们保持语义等价,但在操作的顺序和选择上有所不同。根据在表上收集的统计信息(大小、键的分布直方图),优化器计算每个查询计划所需工作量的估计值。它选择最有效的计划。
基于成本的优化是启发式的,并且依赖于准确的统计数据。随着查询复杂性的增加,启发式可能会产生不正确的计划,这可能会非常低效。
在这种情况下,可以使用查询提示来强制查询计划中的某些策略,例如连接类型。例如,在通常返回非常小的结果集的查询中,您可能希望强制使用嵌套循环连接。您可能还希望强制表的某个连接顺序。
O/R 映射器(或任何生成 SQL 的工具)会生成自己的查询,该查询通常没有提示信息。如果此查询运行效率低下,您的选项有限,其中一些是:
检查表上的索引。可能您可以添加索引。某些系统(例如最新版本的 Oracle)允许您在多个表中建立索引连接。
一些数据库管理系统(再次想到 Oracle)允许您手动将查询计划与特定查询字符串相关联。查询计划由查询的哈希值缓存。如果查询是参数化的,则基本查询字符串是恒定的,并将解析为相同的哈希值。
作为最后的手段,您可以修改数据库模式,但这只有在您控制应用程序时才有可能。
如果您控制 SQL,则可以提示查询。在实践中,实际需要这样做是相当少见的。在具有复杂数据库模式的 O/R 映射器上更常见的故障模式是它们可能难以表达复杂的查询谓词或对大量数据进行复杂的操作。
我倾向于主张将 O/R 映射器用于它适合的 98% 的工作,并在它们是合适的解决方案的地方使用存储过程。如果您确实需要提示查询,那么这可能是合适的策略。除非您的应用程序有什么不寻常的地方(例如某种 DSS),否则您只需要在少数情况下从 O/R 映射器中逃脱。您可能还会发现(同样,一个示例是使用聚合数据的 DSS 工具)O/R 映射器并不是真正适合应用程序的策略。