Hibernate条件查询从数据库表中提取记录需要时间

Hibernate条件查询从数据库表中提取记录需要时间,hibernate,hibernate-mapping,criteria,hibernate-criteria,Hibernate,Hibernate Mapping,Criteria,Hibernate Criteria,在我的项目中,我将向表中插入10000条记录。如果已有任何记录可用,我们将使用hibernate条件获取它,并将其与新记录进行比较。表中的数据非常少,大约有10000条记录。对于hibernate标准,我们已经应用了条件。此hibernate条件正在从表中获取6条记录。但为什么调用criteria.list方法获取6条记录需要时间呢 休眠条件查询: select this_.CLASS_TYPE as CLASS1_15_0_, this_.CLASS_UNIT_TYPE as CLASS2_1

在我的项目中,我将向表中插入10000条记录。如果已有任何记录可用,我们将使用hibernate条件获取它,并将其与新记录进行比较。表中的数据非常少,大约有10000条记录。对于hibernate标准,我们已经应用了条件。此hibernate条件正在从表中获取6条记录。但为什么调用criteria.list方法获取6条记录需要时间呢

休眠条件查询:

select this_.CLASS_TYPE as CLASS1_15_0_, this_.CLASS_UNIT_TYPE as CLASS2_15_0_, this_.CLASS_UNIT_CODE as CLASS3_15_0_, 
this_.ID as ID15_0_, this_.LANG_CODE_ISO as LANG5_15_0_, this_.CTY_CODE_ISO as CTY6_15_0_, this_.NAME as NAME15_0_, this_.INS_DTIME as INS8_15_0_,this_.UPD_DTIME as UPD9_15_0_, this_.DEL_DTIME as DEL10_15_0_ from FI_SALES_LOCATION_V this_ where (this_.CLASS_TYPE='BU' and this_.CLASS_UNIT_TYPE='STO' and this_.CLASS_UNIT_CODE='A1000') and this_.DEL_DTIME is null and ((this_.LANG_CODE_ISO='en' and this_.CTY_CODE_ISO='GB' and this_.ID='A1000') or (this_.LANG_CODE_ISO='en' and this_.CTY_CODE_ISO='GB' and this_.ID='AP1000') or (this_.LANG_CODE_ISO='pt' and this_.CTY_CODE_ISO='PT' and this_.ID='AP1000') or (this_.LANG_CODE_ISO='pt' and this_.CTY_CODE_ISO='PT' and this_.ID='A1000') or (this_.LANG_CODE_ISO='s1' and this_.CTY_CODE_ISO='SI' and this_.ID='AP1000') or (this_.LANG_CODE_ISO='s1' and this_.CTY_CODE_ISO='SI' and this_.ID='A1000'));

尝试以以下方式编写查询:

select this_.CLASS_TYPE as CLASS1_15_0_, this_.CLASS_UNIT_TYPE as CLASS2_15_0_, this_.CLASS_UNIT_CODE as CLASS3_15_0_, 
this_.ID as ID15_0_, this_.LANG_CODE_ISO as LANG5_15_0_, this_.CTY_CODE_ISO as CTY6_15_0_, this_.NAME as NAME15_0_, this_.INS_DTIME as INS8_15_0_,this_.UPD_DTIME as UPD9_15_0_, this_.DEL_DTIME as DEL10_15_0_ 
from FI_SALES_LOCATION_V this_ 
where 
(this_.CLASS_TYPE='BU' and this_.CLASS_UNIT_TYPE='STO' and this_.CLASS_UNIT_CODE='A1000') 
and this_.DEL_DTIME is null 
and (this_.LANG_CODE_ISO='en' and this_.CTY_CODE_ISO='GB' and this_.ID='A1000') 
UNION ALL
select this_.CLASS_TYPE as CLASS1_15_0_, this_.CLASS_UNIT_TYPE as CLASS2_15_0_, this_.CLASS_UNIT_CODE as CLASS3_15_0_, 
this_.ID as ID15_0_, this_.LANG_CODE_ISO as LANG5_15_0_, this_.CTY_CODE_ISO as CTY6_15_0_, this_.NAME as NAME15_0_, this_.INS_DTIME as INS8_15_0_,this_.UPD_DTIME as UPD9_15_0_, this_.DEL_DTIME as DEL10_15_0_ 
from FI_SALES_LOCATION_V this_ 
where 
(this_.CLASS_TYPE='BU' and this_.CLASS_UNIT_TYPE='STO' and this_.CLASS_UNIT_CODE='A1000') 
and this_.DEL_DTIME is null 
and (this_.LANG_CODE_ISO='en' and this_.CTY_CODE_ISO='GB' and this_.ID='AP1000') 
UNION ALL
select this_.CLASS_TYPE as CLASS1_15_0_, this_.CLASS_UNIT_TYPE as CLASS2_15_0_, this_.CLASS_UNIT_CODE as CLASS3_15_0_, 
this_.ID as ID15_0_, this_.LANG_CODE_ISO as LANG5_15_0_, this_.CTY_CODE_ISO as CTY6_15_0_, this_.NAME as NAME15_0_, this_.INS_DTIME as INS8_15_0_,this_.UPD_DTIME as UPD9_15_0_, this_.DEL_DTIME as DEL10_15_0_ 
from FI_SALES_LOCATION_V this_ 
where 
(this_.CLASS_TYPE='BU' and this_.CLASS_UNIT_TYPE='STO' and this_.CLASS_UNIT_CODE='A1000') 
and this_.DEL_DTIME is null 
and (this_.LANG_CODE_ISO='pt' and this_.CTY_CODE_ISO='PT' and this_.ID='AP1000') 
UNION ALL
select this_.CLASS_TYPE as CLASS1_15_0_, this_.CLASS_UNIT_TYPE as CLASS2_15_0_, this_.CLASS_UNIT_CODE as CLASS3_15_0_, 
this_.ID as ID15_0_, this_.LANG_CODE_ISO as LANG5_15_0_, this_.CTY_CODE_ISO as CTY6_15_0_, this_.NAME as NAME15_0_, this_.INS_DTIME as INS8_15_0_,this_.UPD_DTIME as UPD9_15_0_, this_.DEL_DTIME as DEL10_15_0_ 
from FI_SALES_LOCATION_V this_ 
where 
(this_.CLASS_TYPE='BU' and this_.CLASS_UNIT_TYPE='STO' and this_.CLASS_UNIT_CODE='A1000') 
and this_.DEL_DTIME is null 
and (this_.LANG_CODE_ISO='pt' and this_.CTY_CODE_ISO='PT' and this_.ID='A1000') 
UNION  ALL
select this_.CLASS_TYPE as CLASS1_15_0_, this_.CLASS_UNIT_TYPE as CLASS2_15_0_, this_.CLASS_UNIT_CODE as CLASS3_15_0_, 
this_.ID as ID15_0_, this_.LANG_CODE_ISO as LANG5_15_0_, this_.CTY_CODE_ISO as CTY6_15_0_, this_.NAME as NAME15_0_, this_.INS_DTIME as INS8_15_0_,this_.UPD_DTIME as UPD9_15_0_, this_.DEL_DTIME as DEL10_15_0_ 
from FI_SALES_LOCATION_V this_ 
where 
(this_.CLASS_TYPE='BU' and this_.CLASS_UNIT_TYPE='STO' and this_.CLASS_UNIT_CODE='A1000') 
and this_.DEL_DTIME is null 
and (this_.LANG_CODE_ISO='s1' and this_.CTY_CODE_ISO='SI' and this_.ID='AP1000') 
UNION ALL
select this_.CLASS_TYPE as CLASS1_15_0_, this_.CLASS_UNIT_TYPE as CLASS2_15_0_, this_.CLASS_UNIT_CODE as CLASS3_15_0_, 
this_.ID as ID15_0_, this_.LANG_CODE_ISO as LANG5_15_0_, this_.CTY_CODE_ISO as CTY6_15_0_, this_.NAME as NAME15_0_, this_.INS_DTIME as INS8_15_0_,this_.UPD_DTIME as UPD9_15_0_, this_.DEL_DTIME as DEL10_15_0_ 
from FI_SALES_LOCATION_V this_ 
where 
(this_.CLASS_TYPE='BU' and this_.CLASS_UNIT_TYPE='STO' and this_.CLASS_UNIT_CODE='A1000') 
and this_.DEL_DTIME is null 
and (this_.LANG_CODE_ISO='s1' and this_.CTY_CODE_ISO='SI' and this_.ID='A1000');
即使更需要编写,当您执行UNION ALL而不是OR时,性能也会得到提高


或者,您可以为表编制索引,但插入时会降低性能。

考虑到问题和注释中的信息,以下是代码中的内容:

对于要插入的每个记录,都要通过条件进行选择。 进行检查,根据情况,您可以保留或合并记录。 您必须了解hibernate会话在某些情况下的行为。在hibernate中执行操作时,首先要做的是更新hibernate会话。无论是在insert、delete还是update中,操作都将在会话中执行,Hibernate甚至会记录SQL语句,但不会立即刷新到数据库中。是的,这是误导

通常在事务结束时刷新所有内容,但在某些情况下,hibernate将刷新操作以使会话保持最新。在您的情况下,有多条记录要插入/合并,但在每次操作之前都要执行select。Hibernate检测到这个操作,并将刷新以前存储的每个操作,这仅仅是因为如果有挂起的操作要刷新,则查询数据库是没有意义的。数据库需要尽可能处于最新状态。不要试图与之抗争,它是这样设计的

所以我最好的猜测是,当您的选择需要花费太多的时间来执行时,这是因为hibernate正在刷新之前的插入/更新操作

如何解决这个问题:

我想不出任何直接的方法来解决这个问题。你必须重新考虑你的方法

有一件事很重要:即使您只需要在没有任何验证的情况下进行纯插入,您也会遇到一些问题,因为您的代码试图插入数千条记录。这样做的最大问题是,正如我前面所写的,hibernate在事务结束之前不会刷新操作。因此,它将在内存中保存要执行的每个语句。你很有可能会耗尽内存

我要做的第一件事是检查hibernate文档的批处理,从它的。在那之后,我会想出一个策略来优化插入大量记录和所需验证的需求。 与其处理单个记录,不如处理数据块

根据现有的少量信息,我将尝试以下工作流:

首先,再次定义hibernate的batch size属性,检查批处理文档

在处理数据时,使用为批处理大小定义的相同大小对数据进行切片 执行选择,选择要插入的记录中要验证的所有可能记录 执行所需的验证,以检查切片中的每条记录是合并还是插入 组插入和合并并执行操作。刷新并清除休眠会话 获取下一个数据片段,并重复该过程
基本上,这与您正在执行的过程相同,但它将针对大块记录执行,而不是在每条记录中执行。

您确定是hibernate需要时间吗?您是否尝试直接在数据库控制台上调用此SQL查询(它不是hibernate条件查询)?如果这不需要时间,我想知道使用的DBMS的公司名称或产品名称。因为他们发明了一种创新的、具有破坏性的技术。如果我在数据库控制台中执行相同的查询,我马上就能得到结果。您能描述一下如何插入记录和验证现有记录吗?是否通过“持久化/保存”插入每条记录?您是否在会话工厂中配置了批处理?是否在每次插入后验证表?首先,如果记录已可用或不可用,我们将从表中获取记录。如果该记录可用,我们将更新该记录的任何更新。否则,我们将在表中插入新记录。是的,我们将在插入表后进行验证。我们正在使用合并方法更新和插入。上面的查询是由hibernate在运行时生成的。然后,最好的方法是在表上创建一个包含以下列的索引:LANG_CODE_ISO,CTY_CODE_ISO,ID。性能将在OR条件上得到改进。您好,在创建条件之前,我将删除
已在会话中可用,则性能得到改善映射实体=SessionImplementor getSession.getPersistenceContext.getEntityEntries;如果实体!=空实体。清除;看起来您正在清除会话,但以我以前从未见过的方式,通常我会看到session.clear或entityManager.clear。在清除会话/实体管理器之前刷新它是很重要的,否则您将面临失去一致性的风险。我倾向于说这是不正确的。如果你打算这样做,做一轮认真的测试。