糟糕的Hibernate选择性能与直接运行相比 - 如何调试?

时间:2012-11-09 10:43:59

标签: sql performance oracle hibernate

这让我发疯了。与直接通过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-120ms。在远程 databasem,本地JBoss(相同数据)上运行时,导致时间在30000-40000ms之间。当我使用Navicat运行此查询时,本地和远程调用都非常快(20-30ms)。

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

可能是这种糟糕表现的问题?我该如何调试呢?

阅读:Simple hibernate query returning very slowly,但设置构造函数没有改变任何内容

EDIT。

SALES_UNIT 表包含一些基本信息abot销售单位节点,例如名称等。唯一的关联是表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

2 个答案:

答案 0 :(得分: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 s.* ...,第二个是select * ...。这就是这种糟糕表现的原因。现在两个查询都很快就完成了。问题是,有什么区别:performance issue: difference between select s.* vs select *

答案 1 :(得分:2)

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

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

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

此外,

虽然在您的问题中无法确切知道信息,但我认为您想要查询没有子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过滤的列。如果这真的是你想要的,那么你也可以把它写成INNER JOIN而不用WHERE子句,对吗?

最后,

  

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

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