所以,昨天,我被要求修复我们系统中的性能问题: 执行时某次搜索超过了超时(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
子句,同时使用LEFT
或INNER
联接返回相同的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 JOIN
和ORDER BY
的组合会使查询挂起,但删除相同的查询却不会?
为什么直接使用JDBC运行相同的查询不会挂起?
哦,是的,我也尝试将所有三个不同实体中的所有@OneToMany关系更改为FetchType.LAZY
无效(原始实体正在使用FetchMode.SUBSELECT
,原因我不知道。)
更新:
我试过adding full constructors to the Entity classes,因为我正在尝试任何事情,真的,但仍然没有区别。
似乎问题实际上是LEFT JOIN
和ORDER BY
的组合。但不知道为什么。
任何想法,无论多么深远都是受欢迎的,我自己也没有想法。谢谢你的时间!