Performance 使用HibernateCritera API和;Oracle-性能

Performance 使用HibernateCritera API和;Oracle-性能,performance,oracle,hibernate,dynamicquery,Performance,Oracle,Hibernate,Dynamicquery,我必须使用Hibernate并从Oracle检索数据,但问题是,传递给查询的参数数量并不总是相同的 为了简单起见,我们考虑下面的查询: 从选项卡1中选择列1,列2,…,列N,其中列1位于(?,,…) 在子句中传递给的参数数介于1和500之间。如果数字大约为1-50,则运行速度相当快,但对于200,执行查询需要几秒钟(解析、创建解释计划、执行查询)。已创建并使用索引-已对其进行检查 查询是动态创建的,因此我使用Hibernate Criteria API。对于第一个查询(参数>100个),它需要3

我必须使用Hibernate并从Oracle检索数据,但问题是,传递给查询的参数数量并不总是相同的

为了简单起见,我们考虑下面的查询:


从选项卡1中选择列1,列2,…,列N,其中列1位于(?,,…)

在子句中传递给的参数数介于1和500之间。如果数字大约为1-50,则运行速度相当快,但对于200,执行查询需要几秒钟(解析、创建解释计划、执行查询)。已创建并使用索引-已对其进行检查

查询是动态创建的,因此我使用Hibernate Criteria API。对于第一个查询(参数>100个),它需要3-5秒,但是对于下一个查询,它工作得更快(即使参数的数量不同)。我想提高第一个查询的响应时间。在这种情况下,假设必须休眠,我该怎么办

我考虑过removig这个动态查询,例如在xml文件中创建一些静态查询作为命名查询(在这种情况下,这些查询将在开始时预编译)

1) 如果参数数量少于50,则执行一次查询

在这种情况下,如果我们有30个参数,则查询将如下所示:


从列1所在的选项卡1中选择列1、列2、…、列N(列1、列2、…、列30、-1、-1?)

2) 如果数字介于50和100之间,则为第二个数字,以此类推

问题在于,使用命名查询和HQL(在JDBC中,这将是非常简单的)并不是那么简单。在HQL中,我们只传递了一个列表,并且没有在该列表中指定多个参数,即实际上只有一个查询

'from Person where id in (:person_list)'

myQuery.setParameterList("person_list", myList)
有什么办法可以解决这个问题吗

顺便说一下,我认为解释计划是针对每个新查询执行的,例如:


(a) 从选项卡1中选择列1、列2、…、列N,其中必须创建(?、、、…、?)-解释计划中的列1


(b) 从选项卡1中选择列1、列2、…、列N,因为缓存中已存在列1,所以不会创建(?、、…、?)-解释计划中的列1


(c) 从选项卡1中选择COL_1、COL_2、…、COL_N,其中应创建(?、、…、?)-解释计划中的COL_1(对于具有120个参数的查询,没有解释计划),但与(a)相比所需时间更短,几乎与(b)相同,因此如果以前执行过类似的查询,Oracle可能可以更快地创建此计划


原因是什么?

这里有几件事。首先,你不能在列表中绑定,至少我很确定你不能。我怀疑Hibernate在使用某种技巧,将数组内容放入Oracle可以使用的静态inlist中

其次,如果使用许多不同的参数执行此查询,则必须绑定变量,否则整个数据库的性能将受到影响

这就是说,有一种方法可以使用Tom Kyte在其博客中描述的“技巧”绑定入列表:

其中的代码如下所示:

ops$tkyte@ORA10GR2> with bound_inlist
2  as
3  (
4  select
5    substr(txt,
6           instr (txt, ',', 1, level  ) + 1,
7           instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1 )
8           as token
9    from (select ','||:txt||',' txt from dual)
10  connect by level <= length(:txt)-length(replace(:txt,',',''))+1
11  )
12  select *
13    from all_users
14   where user_id in (select * from bound_inlist);

USERNAME                          USER_ID CREATED
------------------------------ ---------- ---------
SYSTEM                                  5 30-JUN-05
OPS$TKYTE                             104 20-JAN-06
基本上就是查询的目的地。上面的一位是将逗号分隔的字符串拆分为值列表的技巧。您不需要将列表绑定到:txt占位符中,而需要将列表转换为字符串,并仅绑定该字符串


您确定查询时间的差异不是由于计算机上的缓存或负载变化造成的吗?解析查询需要一点时间,但几秒钟是很长的时间。

这里有几件事。首先,你不能在列表中绑定,至少我很确定你不能。我怀疑Hibernate在使用某种技巧,将数组内容放入Oracle可以使用的静态inlist中

其次,如果使用许多不同的参数执行此查询,则必须绑定变量,否则整个数据库的性能将受到影响

这就是说,有一种方法可以使用Tom Kyte在其博客中描述的“技巧”绑定入列表:

其中的代码如下所示:

ops$tkyte@ORA10GR2> with bound_inlist
2  as
3  (
4  select
5    substr(txt,
6           instr (txt, ',', 1, level  ) + 1,
7           instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1 )
8           as token
9    from (select ','||:txt||',' txt from dual)
10  connect by level <= length(:txt)-length(replace(:txt,',',''))+1
11  )
12  select *
13    from all_users
14   where user_id in (select * from bound_inlist);

USERNAME                          USER_ID CREATED
------------------------------ ---------- ---------
SYSTEM                                  5 30-JUN-05
OPS$TKYTE                             104 20-JAN-06
基本上就是查询的目的地。上面的一位是将逗号分隔的字符串拆分为值列表的技巧。您不需要将列表绑定到:txt占位符中,而需要将列表转换为字符串,并仅绑定该字符串

您确定查询时间的差异不是由于计算机上的缓存或负载变化造成的吗?解析查询需要一点时间,但几秒钟是很长的时间。

我在(…)查询中使用了
,该列表中最多有1000个ID;我可以向您保证,解析/准备/缓存语句不需要几秒钟

Hibernate确实会使用您传递的列表中的实际元素数自动扩展您指定的参数列表,因此如果您真的想将其“固定”在某个级别,那么您需要做的就是在末尾添加足够的-1。但是,这肯定不是问题所在,特别是因为我们正在讨论如何加快第一次查询的运行速度-无论如何,还没有准备/缓存任何语句

您是否查看了查询的执行计划?是否同时启用了“解释计划”和“自动追踪”?当列表中有30个元素和120个元素时,它们是否不同?您的actual查询是否真的像您发布的“从id所在的表中选择…”,还是更复杂?我敢打赌,在30到120个元素之间,Oracle决定(可能是错误地)不使用索引会更快,这就是为什么您会看到时间在增加。

我在(…)
查询中使用了
,该列表中有多达1000个ID;我可以向您保证,解析/准备/缓存语句不需要几秒钟

Hibernate确实会使用您传递的列表中的实际元素数自动扩展您指定的参数列表,因此如果您真的想将其“固定”在某个特定的位置