当 HQL 查询使用 "OR" 条件时,如何强制 Oracle 使用索引然后联合而不是完整 table 扫描?
How can I enforce Oracle to use index and then union instead of full table scan when HQL query is using "OR" condition?
伙计们:
我有一个用 HQL 编写的查询,它使用 2 个 OR 条件来合并 "where" 子句部分中的结果。 Hibernate 框架获取结果非常慢,因为它对 table DboX 进行了完整的 table 扫描,其中包含大量行。我想提高HQL的查询性能。
我在 Toad 上测试了类似 sql 的查询,发现如果我使用 union 和 3 个子查询而不是 "OR" 条件会更快。
TypedQuery<DboX> query = this.getTypedQuery(
"from DboX where ( segId in ( "
+ "select segId from DboY "
+ "where fpId.controlNumber = :fpIdControlNumber "
+ "and fpId.amendmentNumber = :fpIdAmendmentNumber "
+ " ) or segId in ( "
+ "select id from DboZ "
+ "where fpId.controlNumber = :fpIdControlNumber "
+ "and fpId.amendmentNumber = :fpIdAmendmentNumber "
+ " ) or mfUuid in ( "
+ " select uuid from DboU "
+ "where uSegId in ( "
+ "select segId from DboY "
+ "where fpId.controlNumber = :fpIdControlNumber "
+ "and fpId.amendmentNumber = :fpIdAmendmentNumber "
+ " ) ) ) and dataSourceName = 'aaaa' and oId is not null"
+ " order by oId");
query.setParameter("fpControlNumber", id.getControlNumber());
query.setParameter("fpIdAmendmentNumber", id.getAmendmentNumber());
return super.search(query);
但是,HQL 不支持联合,我也不允许更新 java 代码以将结果与 HQL 的 3 种方法合并,因为我们的代码被冻结了。我的经理更喜欢在后端 oracle 数据库实例上进行更改,而不是 java 代码。有人对此有什么建议吗?
首先要确认Oracle数据库有更新统计信息!如果幸运的话,统计数据已经过时,现有查询在更新时会突然选择一个更好的计划。
否则,如果允许您更改代码,您可以对您在 Toad 中测试的 SQL 使用本机查询。这很好,因为您知道您将获得您测试过的 SQL,并且不受 HQL 的限制。
如果您至少被允许更改 HQL(它也是我书中的代码),您可以添加提示并指示 Oracle 使用您想要的索引。总的来说,我不喜欢提示,但它们有它们的用武之地。也许这就是其中之一。
最后,如果您真的无法访问该应用程序,您可以尝试使用 Oracle 中的 SQL 配置文件来强制执行您想要的计划。 Manual creation of a SQL Profile 解释了如果企业管理器无法执行您想要的操作,如何手动创建一个。无论如何,这是您需要与 DBA 讨论的事情。它需要企业版加上 "Tuning Pack".
伙计们:
我有一个用 HQL 编写的查询,它使用 2 个 OR 条件来合并 "where" 子句部分中的结果。 Hibernate 框架获取结果非常慢,因为它对 table DboX 进行了完整的 table 扫描,其中包含大量行。我想提高HQL的查询性能。
我在 Toad 上测试了类似 sql 的查询,发现如果我使用 union 和 3 个子查询而不是 "OR" 条件会更快。
TypedQuery<DboX> query = this.getTypedQuery(
"from DboX where ( segId in ( "
+ "select segId from DboY "
+ "where fpId.controlNumber = :fpIdControlNumber "
+ "and fpId.amendmentNumber = :fpIdAmendmentNumber "
+ " ) or segId in ( "
+ "select id from DboZ "
+ "where fpId.controlNumber = :fpIdControlNumber "
+ "and fpId.amendmentNumber = :fpIdAmendmentNumber "
+ " ) or mfUuid in ( "
+ " select uuid from DboU "
+ "where uSegId in ( "
+ "select segId from DboY "
+ "where fpId.controlNumber = :fpIdControlNumber "
+ "and fpId.amendmentNumber = :fpIdAmendmentNumber "
+ " ) ) ) and dataSourceName = 'aaaa' and oId is not null"
+ " order by oId");
query.setParameter("fpControlNumber", id.getControlNumber());
query.setParameter("fpIdAmendmentNumber", id.getAmendmentNumber());
return super.search(query);
但是,HQL 不支持联合,我也不允许更新 java 代码以将结果与 HQL 的 3 种方法合并,因为我们的代码被冻结了。我的经理更喜欢在后端 oracle 数据库实例上进行更改,而不是 java 代码。有人对此有什么建议吗?
首先要确认Oracle数据库有更新统计信息!如果幸运的话,统计数据已经过时,现有查询在更新时会突然选择一个更好的计划。
否则,如果允许您更改代码,您可以对您在 Toad 中测试的 SQL 使用本机查询。这很好,因为您知道您将获得您测试过的 SQL,并且不受 HQL 的限制。
如果您至少被允许更改 HQL(它也是我书中的代码),您可以添加提示并指示 Oracle 使用您想要的索引。总的来说,我不喜欢提示,但它们有它们的用武之地。也许这就是其中之一。
最后,如果您真的无法访问该应用程序,您可以尝试使用 Oracle 中的 SQL 配置文件来强制执行您想要的计划。 Manual creation of a SQL Profile 解释了如果企业管理器无法执行您想要的操作,如何手动创建一个。无论如何,这是您需要与 DBA 讨论的事情。它需要企业版加上 "Tuning Pack".