休眠为每个查询生成不同的 SQL

2022-09-02 02:05:00

我刚刚在探查器下测试了我的应用程序,发现sql字符串占用了我大约30%的内存!这很奇怪。

有很多这样的字符串存储在应用程序内存中。这是由休眠生成的SQL查询,请注意不同的数字和尾随下划线:

select avatardata0_.Id as Id4305_0_,...... where avatardata0_.Id=? for update
select avatardata0_.Id as Id4347_0_,...... where avatardata0_.Id=? for update

这是我无法理解的部分。为什么休眠必须为每个查询生成具有不同标识符(如“Id4305_0_”)的不同sql字符串?为什么它不能对所有相同的查询使用一个查询字符串?这是绕过查询缓存的某种技巧吗?

如果有人能描述一下为什么会发生这种情况以及如何避免这种资源浪费,我将不胜感激。

更新

还行。我找到了。我错误地假设内存泄漏,这是我的错。休眠按预期工作。

我的应用程序已创建 121(!)SessionFactories在10个线程中,他们生产了大约2300个SingleTableEntityPersisters实例。每个 SingleTableEntityPersister 使用不同的标识符生成大约 15 个 SQL 查询。Hibernate被迫生成大约345.000个不同的SQL查询。一切都很好,没有什么奇怪的:)


答案 1

休眠生成的查询字符串后面有一个逻辑。其主要目的是获取表名和列名的唯一别名。

从您的查询中,

select avatardata0_.Id as Id4305_0_,...... where avatardata0_.Id=?

avatardata0_ ==> avatardata是表的别名,并追加以指示它是查询中的第一个表。因此,如果它是查询中的第二个表(或实体),则应显示为 .它对列别名使用相同的逻辑。0_avatardata1_

因此,通过这种方式可以避免所有可能的冲突。

您看到这些查询,因为您已打开标记配置。这用于调试查询。一旦你的应用程序开始工作,你应该把它关掉。show_sql

在此处阅读有关 API 文档的更多信息

我不太了解内存消耗部分,但是您在关闭上述标志的情况下重复测试,看看是否有任何改进。


答案 2

假设您使用的是 sql Server,则可能需要检查参数类型声明中的 “?”,确保声明每次都产生相同的固定长度声明。

动态长度参数将导致每个查询都有单独的执行计划。这可能会消耗大量资源。我们看到的是相同的过程,get 被 sql server 解释为不同的查询,呈现一个单独的执行计划。

因此

exec myprocedure @p1 varchar(3)='foo' 

exec myprocedure @p1 varchar(6)='foobar' 

将导致不同的计划。仅仅因为@p1的声明在大小上有所不同。

关于这种行为有很多需要了解的地方。如果上述内容适用于您,我建议您阅读“参数嗅探”。


推荐