Hibernate Criteria与HQL:哪个更快?

72
我阅读了一些答案,但仍感到困惑。为什么?因为你提到的区别与性能无关,而是与易用性有关(如Objetc(criteria)和SQL(hql))。但我想知道是否由于某种原因,“criteria”比hql慢。
我在另一个回答中读到这个:
“使用criteriaQuery查询时,在表名上每次都会创建一个新的别名,这不会反映在任何数据库的最后查询缓存中。这会导致编译生成的SQL的开销增加,执行时间更长。”——Varun Mehta。
这非常接近!但是我在另一个网站上(http://gary-rowe.com/agilestack/tag/hibernate/)读到:Hibernate 3.3及以上版本已不再如此(请阅读此处:9)Hibernate很慢,因为Criteria接口生成的SQL不一致。
我做了一些测试,尝试找出差异,但两者都会生成查询,并且不会更改表的别名。
我很困惑。如果有人知道主要原因,请帮助我们。谢谢
5个回答

157

我是2004年编写了Hibernate 3查询转换器的人,所以我对它的工作方式有所了解。

理论上,Criteria 的开销应该比 HQL 查询小(除了命名查询,我会在后面提到)。这是因为 Criteria 不需要解析任何内容。HQL 查询使用基于 ANTLR 的解析器进行解析,然后将生成的 AST 转换为 SQL。但是,使用 HQL/JPAQL 可以定义命名查询,其中 SQL 是在 SessionFactory 启动时生成的。理论上,命名查询的开销比 Criteria 小。

因此,就 SQL 生成开销而言,我们有以下几种情况:

  1. 命名 HQL/JPAQL 查询 - SQL 仅生成一次。
  2. Criteria - 无需解析即可生成。
  3. (非命名)HQL/JPAQL 查询 - 解析后生成。

话虽如此,基于解析和 SQL 生成开销选择查询技术可能是一个错误,在我看来。与在真实数据库服务器上执行真实查询时相比,这种开销通常非常小。如果这种开销确实在应用程序分析中显示出来,则也许您应该切换到命名查询。

这里是我在决定使用 Criteria 和 HQL/JPAQL 之间考虑的事情:

  • 首先,您必须决定是否可以接受在代码中依赖于 Hibernate 专有 API 。JPA 没有 Criteria。
  • Criteria 在处理许多可选搜索参数方面非常出色,例如您可能会在具有多个参数的典型 Web 页面的“搜索表单”中找到的情况。使用 HQL,开发人员往往会使用 StringBuilder 添加 where 子句表达式(避免这样做!)。使用 Criteria,您不需要这样做。Hardik 发表了类似的观点。
  • HQL/JPAQL 可用于大多数其他事情,因为代码往往更短,开发人员更容易理解。
  • 如果你使用HQL,可以将经常性的查询转换为命名查询。但我更喜欢在一些分析之后再这样做。

  • JPA没有Criteria。 - destan
    3
    从JPA 2.x版本开始支持,如果我没记错的话,JPA 1.x并不支持。 - Joshua Davis
    2
    @bruno.zambiazi 如果您正在通过字符串拼接构建JPAQL/HQL,则很可能您有一个动态查询,这就是Criteria查询功能的用途。我倾向于对任何动态内容(例如,查询根据用户输入而变化很大)使用Criteria。希望对您有所帮助 - Josh - Joshua Davis
    连接表时哪种方式更快? - user9845730
    1
    @GokulRajK.N. 从Criteria或JPQL生成SQL时,显式或隐式连接应该没有太大区别。通常,执行连接所需的时间比生成SQL要长得多,因此在大多数情况下,在两者之间切换不会产生明显的差异。 - Joshua Davis
    显示剩余2条评论

    10

    我正在处理数百万条记录。我发现 HQL 比 Criteria 快得多。Criteria 的性能明显滞后。

    如果你需要处理大量数据,则选择 HQL。


    5
    这对我来说意义不大。如果你有一个非常大的数据集,那么大部分时间都花在等待数据库处理查询上。在这种情况下,从HQL或Criteria生成SQL所需的时间并不重要。仅当您执行相同查询多次时,才需要使用JPAQL命名查询与“直接”JPAQL或Criteria进行比较。数据集的大小根本不重要。 - Joshua Davis
    2
    也许您没有正确使用Criteria。或者您为数百万条记录创建了新的Criteria查询对象吗? - vinodn
    1
    生成的 SQL 访问计划可能不同,但这并不意味着是 Criteria 的错误。 - Lluis Martinez

    7
    我更倾向于使用Criteria Queries来进行动态查询。例如,根据某些参数动态添加排序或者留下某些部分(例如限制条件)要容易得多。
    另一方面,我使用HQL来处理静态和复杂的查询,因为理解/阅读HQL要容易得多。此外,我认为HQL更加强大,例如针对不同的连接类型。
    参考链接:JPA和Hibernate-Criteria vs. JPQL或HQL

    4
    标准查询语言(Criteria)可以完成大部分 HQL 查询类型,尽管有时候可能会有点别扭或难以理解(至少在我个人看来是这样)。关于 HQL 更易读的观点完全正确! - Joshua Davis
    1
    顺便说一句,我会投票支持你的回答...但是你并没有真正回答kcobuntu的问题。 - Joshua Davis
    31
    如果你要抄袭别人的答案,至少应该提及一下原作者。 原始答案链接:https://dev59.com/-nVC5IYBdhLWcg3wvT1a#197496 - Soroush Mirzaei
    嗯...当时我还是个新手,而且 Stack Overflow 上也没有太多用户/版主。 - Hardik Mishra
    关键的区别在于提到了Hibernate类(Criteris)和查询表达式(HQL)的问题,表达式在运行时被解析和准备执行,而Criteria是一个构建对象,最终生成语句。基准测试并没有太大的差异。还有其他的差异,这些差异与常见的设计更相关。当定义实体时,HQL查询可以被定义为命名查询,也可以在JSON属性中定义。 - Simon

    6

    我认为Criteria比HQL更有优势的其他方面包括:

    HQL编写会让代码变得混乱。 它看起来不像是编写干净的面向对象代码。

    而在编写Criteria查询时,IDE会自动提示功能,因此除非我们将变量名称用双引号括起来,否则出错的概率较小。


    5
    对于复杂查询,HQL比Criteria更易读。 - Lluis Martinez

    4

    你说得没错,也有一些不准确的地方。结果列表是使用org.hibernate.loader.Loader类从数据库或缓存中检索的。当缓存未启用时,将使用在SessionFactoryImp中创建的Dialect对象构建prepared statement。因此,语句会在每次调用列表时初始化。

    此外,低级查询会自动生成。基本上,这是一个辅助工具,但在手动编写特定查询更有效的情况下,可能需要使用手动编写查询。


    HQL是一个表达式,它被解析并准备为语句。Criteria是一个构建对象,最终为当前JDBC驱动程序创建一个SQL查询。它们在性能上没有太大区别。然而,当HQL被重复使用时,它可能会更快。 - Simon

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接