8

这让我疯狂。与直接通过 Navicat 运行该查询相比,使 hibernate 简单选择非常慢。还有什么更有趣的。使用本地数据库运行此查询非常快,但远程使用它真的很差。

我正在执行 Hibernate 本机 SQL 查询(因为 HQL 或 Criteria 不支持左连接):

List list = new ArrayList();
String queryStr = "select s.* from sales_unit s left join sales_unit_relation r on (s.sales_unit_id = r.sales_unit_child_id) where r.sales_unit_child_id is null";
Query query = session.createSQLQuery( queryStr ).addEntity( SalesUnit.class );

Long start = System.currentTimeMillis();
list.addAll( query.list() );
Long stop = System.currentTimeMillis();
System.out.println( "Time: " + (stop - start) + "ms." );

实体的结构并不重要。SALES_UNIT 和 SALES_UNIT_RELATION 表都有大约 28k 条记录

使用本地数据库在我的本地 JBoss上运行的结果约为 30-120 毫秒。在远程数据库上运行时,本地 JBoss(相同数据)导致时间在 30000-40000 毫秒之间。当我使用 Navicat 运行这个查询时,本地和远程调用都非常快(20-30 毫秒)。

本地和远程数据库的安装方式相同 -> Oracle Enterprise Edition 11.2.0.1.0。

性能如此差的问题可能是什么?我该如何调试它?

阅读本文:简单的休眠查询返回速度很慢,但设置构造函数并没有改变任何东西

编辑。

SALES_UNIT表包含一些关于销售单元节点的基本信息,例如名称等。唯一的关联是与表 SALES_UNIT_TYPE,如 ManyToOne。主键是 ID,字段 VALID_FROM_DTTM 是日期。

SALES_UNIT_RELATION包含销售单元节点之间的关系 PARENT-CHILD。由 SALES_UNIT_PARENT_ID、SALES_UNIT_CHILD_ID 和 VALID_TO_DTTM/VALID_FROM_DTTM 组成。与任何表没有关联。这里的PK是..PARENT_ID、..CHILD_ID和VALID_FROM_DTTM

4

2 回答 2

3

谢谢大家的帮助。经过长时间的努力解决这个问题,最后 kaliatech 的回答帮助我调试了这个问题。

首先,我在我的问题中犯了一个可怕的错误。我写道:

使用本地数据库运行此查询非常快,但远程使用它真的很差。

因为它并不完全正确。我在 Hibernate 中所做的查询看起来像一个:

select s.* from sales_unit s left join sales_unit_relation r on (s.sales_unit_id = r.sales_unit_child_id) where r.sales_unit_child_id is null

但我使用 SQL PLus 或 Navicat 进行的实际查询是:

select * from sales_unit s left join sales_unit_relation r on (s.sales_unit_id = r.sales_unit_child_id) where r.sales_unit_child_id is null

请注意,第一个查询 select 开始:select s.* ...第二个是select * .... 这就是表现如此糟糕的原因。现在两个查询都很快完成了。问题是,有什么区别:性能问题:select s.* 与 select * 之间的区别

于 2012-11-15T13:15:18.717 回答
2

要获得明确的答案,我认为需要更多信息。主要是:

  • SalesUnit 实体类中是否有任何实体关联或集合字段?<-- 这是我对您所看到的性能差异的第一个猜测,而不是任何其他信息。

  • 在非 Hibernate 环境中使用相同的 JDBC 驱动程序运行查询时,您是否有相同的性能问题?(即使用像DbVisualizer这样的第 3 方 JDBC 客户端)。

还,

尽管无法确定问题中的信息,但我认为您想查询所有没有子 SalesUnit 的 SalesUnit。正确的?(这取决于您使用 sales_unit_relation 表的目的。)如果是这样,您可以这样编写查询:

String queryStr = "select s.* from sales_unit s
                   left join sales_unit_relation r on 
                   (s.sales_unit_id = r.sales_unit_child_id)
                   where r.sales_unit_child_id is null";

但是,我认为您可能想要更像这样的东西:

String queryStr = "select s.* from sales_unit s
                   left join sales_unit_relation r on 
                   (s.sales_unit_id = r.sales_unit_id)
                   where r.sales_unit_child_id is null";

照原样,您的查询正在加入您在 WHERE 子句中过滤为 null 的列。如果这确实是您想要的,那么您也可以将其编写为不带 WHERE 子句的 INNER JOIN,对吗?

最后,

我正在执行 Hibernate 本机 SQL 查询(因为 HQL 或 Criteria 不支持左连接)

如前所述,这是不正确的。只有当被查询的实体/表之间没有映射关系时,HQL 和 Criteria 才支持左连接。因此,根据您的示例,假设 SalesUnit 与 sales_unit_relation 表所代表的任何实体/关联之间没有映射的实体关系。(无论如何,本机查询应该可以工作,但是如果存在映射关系,那么使用 HQL/Criteria 的一个好处是您可以执行left join fetch.)

于 2012-11-14T16:45:53.997 回答