这让我发疯了。与直接通过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
答案 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
。)