当LEFTJOIN用于处理ORDER BY时,为什么hibernate需要太长时间?

时间:2015-07-10 13:21:03

标签: java sql-server performance hibernate jdbc

所以,昨天,我被要求修复我们系统中的性能问题: 执行时某次搜索超过了超时(600s)。

我做的第一件事是挖掘哪个DAO正在执行搜索,并发现它使用以下hibernate查询:

    SELECT DISTINCT u FROM TripLogHeader u  
    LEFT JOIN u.eventHeaderSet ug  
    LEFT JOIN ug.eventLocomotiveTrainSet elts  
    WHERE 1 = 1  
        AND elts.eventLocomotiveTrainPrefix LIKE :eventLocomotiveTrainPrefix  
        AND u.tripLogStateId.tripLogStateId >= :tripLogStateGreaterOrEqual 
    ORDER BY u.tripLogHeaderId DESC

我的直觉告诉我: 由于此查询仅返回设置了eventLocomotiveTrainPrefix的结果,因此,我们不需要LEFT JOIN,而简单的JOIN可以解决问题。

嗯,这很有效,超过600秒的查询以毫秒为单位返回,使用普通JOIN代替LEFT JOIN

但是 为什么

我的第一个假设是数据库花了太长时间才能返回所有结果,因此我进行了一些测试以试图证明:

使用WHERE在没有LEFT JOIN子句的数据库上运行简单的SQL查询,返回大约10万个结果,以毫秒为单位。

运行相同的SQL查询,没有WHERE子句,使用INNER JOIN,返回大约1千个结果,以毫秒为单位。

添加WHERE子句,同时使用LEFTINNER联接返回相同的40个结果,均以毫秒为单位。

进行一些研究,我看到有人告诉尝试在没有ORDER BY子句的情况下运行查询。这样做了,LEFT JOIN的结果仍然是毫秒!

我无法弄清楚为什么LEFT JOIN + ORDER BY导致查询超时,而当他们自己使用的任何内容都不会超时时。

此外,hibernate(hibernate.show_sql = true)生成的查询如下:

Hibernate: 
select
    distinct top 20 triploghea0_.trip_log_header_id as trip_log1_62_,
    triploghea0_.event_header_timestamp_begin as event_he2_62_,
    triploghea0_.event_header_timestamp_end as event_he3_62_,
    triploghea0_.map_block_name_destination as map_bloc4_62_,
    triploghea0_.map_block_name_origin as map_bloc5_62_,
    triploghea0_.own_rollingstock_entry_tag as own_roll6_62_,
    triploghea0_.trip_log_header_adherence as trip_log7_62_,
    triploghea0_.trip_log_header_consumption as trip_log8_62_,
    triploghea0_.trip_log_header_distance as trip_log9_62_,
    triploghea0_.trip_log_header_eficiency as trip_lo10_62_,
    triploghea0_.trip_log_header_flush_tstamp as trip_lo11_62_,
    triploghea0_.trip_log_header_stoped_time as trip_lo12_62_,
    triploghea0_.trip_log_header_total_time as trip_lo13_62_,
    triploghea0_.trip_log_state_id as trip_lo15_62_,
    triploghea0_.user_entry_registry as user_en14_62_ 
from
    trip_log_header triploghea0_ 
left outer join
    event_header eventheade1_ 
        on triploghea0_.trip_log_header_id=eventheade1_.trip_log_header_id 
left outer join
    event_loco_train eventlocom2_ 
        on eventheade1_.event_header_id=eventlocom2_.event_header_id 
where
    1=1 
    and (
        eventlocom2_.event_loco_train_prefix like ?
    ) 
    and triploghea0_.trip_log_state_id>=? 
order by
    triploghea0_.trip_log_header_id desc

在数据库中运行该查询,通过Netbeans使用相同的JDBC,也会带来相同的40个结果,以毫秒为单位。

如果数据库不是表现不佳的数据库,那是什么? 这听起来很可疑,所以我去研究了一些。找到了有关MS SQL Server driver actually changing the way the query was sent的有趣内容。我更改了驱动程序,测试了驱动程序中可能的所有选项。没什么,虚无...同样的行为一遍又一遍。

Trying changing SQL Server's query plan configuration但仍然没有变化。

我很无能为力。为什么Hibernate上LEFT JOINORDER BY的组合会使查询挂起,但删除相同的查询却不会? 为什么直接使用JDBC运行相同的查询不会挂起?

哦,是的,我也尝试将所有三个不同实体中的所有@OneToMany关系更改为FetchType.LAZY无效(原始实体正在使用FetchMode.SUBSELECT,原因我不知道。)

更新:

我试过adding full constructors to the Entity classes,因为我正在尝试任何事情,真的,但仍然没有区别。

似乎问题实际上是LEFT JOINORDER BY的组合。但不知道为什么。

任何想法,无论多么深远都是受欢迎的,我自己也没有想法。谢谢你的时间!

0 个答案:

没有答案