5

我是 ORM 解决方案的倡导者,有时我会举办有关 Hibernate 的研讨会。

在谈论框架生成的 SQL 时,人们通常会开始谈论他们需要如何使用“提示”,而这对于 ORM 框架来说是不可能的。

通常是这样的:“我们尝试过 Hibernate。一开始它看起来很有希望,但是当我们让它在我们非常复杂的生产数据库上松动时,它就崩溃了,因为我们无法应用提示!”。

但是当被问到一个具体的例子时,那些人的记忆突然变得不那么清晰了……

我通常会感到害怕,因为整个“提示”主题对我来说听起来像是伏都教......所以有人可以启发我吗?SQL 提示或 DB 提示是什么意思?

我唯一知道的,某种程度上“类似提示”的是 SELECT ... FOR UPDATE。但这得到了 Hibernate-API 的支持......

4

5 回答 5

12

SQL 语句,尤其是复杂的 SQL 语句,实际上可以由数据库引擎以多种不同的方式执行(首先读取连接中的哪个表,根据许多不同的参数使用哪个索引等)。

有经验的 dba 可以使用提示来鼓励DB 引擎在生成其执行计划时选择特定的方法。您通常只需要在对特定查询进行广泛测试和分析后执行此操作(因为数据库引擎通常非常擅长找出最佳执行计划)。

这里有一些特定于 MSSQL 的讨论和语法:http:
//msdn.microsoft.com/en-us/library/ms181714.aspx

编辑: http://geeks.netindonesia.net/blogs/kasim.wirama/archive/2007/12/31/sql-server-2005-query-hints.aspx的一些附加示例

于 2008-11-04T14:25:52.347 回答
9

默认情况下,查询提示用于指导查询优化器不产生合理的查询计划。首先,查询优化器的小背景:

数据库编程与几乎所有其他软件开发不同,因为它有一个机械组件。与 CPU 相比,磁盘寻道和旋转延迟(等待特定扇区到达磁盘磁头下方)非常昂贵。不同的查询解析策略将导致不同数量的 I/O,通常是完全不同的数量。判断正确或错误会对查询的性能产生重大影响。有关查询优化的概述,请参阅本文。

SQL 是声明性的——您指定查询的逻辑并让 DBMS 弄清楚如何解决它。现代的基于成本的查询优化器(某些系统,例如 Oracle 还保留了旧的查询优化器以实现向后兼容性)将对查询运行一系列转换。它们保持语义等价,但在操作的顺序和选择上有所不同。根据在表上收集的统计信息(大小、键的分布直方图),优化器计算每个查询计划所需工作量的估计值。它选择最有效的计划。

基于成本的优化是启发式的,并且依赖于准确的统计数据。随着查询复杂性的增加,启发式可能会产生不正确的计划,这可能会非常低效。

在这种情况下,可以使用查询提示来强制查询计划中的某些策略,例如连接类型。例如,在通常返回非常小的结果集的查询中,您可能希望强制使用嵌套循环连接。您可能还希望强制表的某个连接顺序。

O/R 映射器(或任何生成 SQL 的工具)会生成自己的查询,该查询通常没有提示信息。如果此查询运行效率低下,您的选项有限,其中一些是:

  • 检查表上的索引。可能您可以添加索引。某些系统(例如最新版本的 Oracle)允许您在多个表中建立索引连接。

  • 一些数据库管理系统(再次想到 Oracle)允许您手动将查询计划与特定查询字符串相关联。查询计划由查询的哈希值缓存。如果查询是参数化的,则基本查询字符串是恒定的,并将解析为相同的哈希值。

  • 作为最后的手段,您可以修改数据库模式,但这只有在您控制应用程序时才有可能。

如果您控制 SQL,则可以提示查询。在实践中,实际需要这样做是相当少见的。在具有复杂数据库模式的 O/R 映射器上更常见的故障模式是它们可能难以表达复杂的查询谓词或对大量数据进行复杂的操作。

我倾向于主张将 O/R 映射器用于它适合的 98% 的工作,并在它们是合适的解决方案的地方使用存储过程。如果您确实需要提示查询,那么这可能是合适的策略。除非您的应用程序有什么不寻常的地方(例如某种 DSS),否则您只需要在少数情况下从 O/R 映射器中逃脱。您可能还会发现(同样,一个示例是使用聚合数据的 DSS 工具)O/R 映射器并不是真正适合应用程序的策略。

于 2008-11-04T15:54:27.613 回答
4

虽然 HINTS 与其他答案描述的一样,但您应该只在极少数经过研究的情况下使用它们。HINT 10 次中有 9 次会导致查询计划不佳。除非你真的知道自己在做什么,否则不要使用它们。

于 2008-11-04T14:31:45.347 回答
3

所有现代 RDBMS-es 都有某种查询优化器来计算最佳查询计划,这是执行 SQL 查询所需的读/写操作序列。

有时计划可能不是最理想的,因此 RDBMS 设计者在 SQL 中包含“提示”。提示是您可以嵌入到影响查询优化器的 SQL 中的指令,通过提示,您可以指示查询优化器,例如它应该使用哪些索引,应该以什么顺序从表中读取数据,......

因此,通过提示,您可以解决一些查询优化器无法自行解决的瓶颈。

例如,这里是Oracle 提示列表。

于 2008-11-04T14:27:39.490 回答
3

没有“优化的 SQL 代码”之类的东西,因为 SQL 代码永远不会被执行。

SQL 代码由优化器转换为执行计划。优化器将使用它必须选择的信息(除其他外)。

  • 涉及表的顺序
  • 每个涉及的表的连接方法(嵌套/合并/散列)
  • 如何访问表的数据(直接表访问/带有书签查找的索引/直接索引访问)(扫描/查找)
  • 应该使用并行性,以及何时结束并行性(收集流)

查询提示允许程序员覆盖(在大多数情况下)或礼貌地建议(在其他情况下)优化器的选择。

查询提示可以让您强制关闭并行性,强制所有连接实现为嵌套循环,强制使用一个索引而不是另一个索引......作为一些示例。

由于优化器非常好,如果一个人超越了优化器,通常会要求一个非最佳计划。当优化器没有做出正确选择所需的信息时,最好使用查询提示。

我使用查询提示的一个地方是表变量。优化器假定表变量有 0 行,因此优化器总是使用嵌套循环连接表变量(少量行的最佳连接实现)。如果我有一个大表变量 - 已经以对合并联接有利的方式排序,我可以通过应用查询提示来指定要使用的合并联接。

于 2008-11-04T16:50:11.587 回答