5

我们有一个在生产环境中运行的 Web 应用程序,并且在某些时候客户抱怨应用程序运行速度有多慢。

当我们检查应用程序和数据库的情况时,我们发现这个“宝贵的”查询正在由多个用户同时执行(从而对数据库服务器造成极高的负载):

SELECT   NULL AS table_cat,
         o.owner AS table_schem,
         o.object_name AS table_name,
         o.object_type AS table_type,
         NULL AS remarks
FROM     all_objects o
WHERE    o.owner LIKE :1 ESCAPE :"SYS_B_0" AND
         o.object_name LIKE :2 ESCAPE :"SYS_B_1" AND
         o.object_type IN(:"SYS_B_2", :"SYS_B_3")
ORDER BY table_type, table_schem, table_name

我们的应用程序没有执行这个查询,我相信它是一个 Hibernate 内部查询。我几乎没有找到关于为什么 Hibernate 会执行这个极其繁重的查询的信息,因此非常感谢任何有关如何避免它的帮助!

生产环境信息:Red Hat Enterprise Linux 5.3 (Tikanga), JDK 1.5, web container OC4J (whitin Oracle Application Server), Oracle Database 10.1.0.4, JDBC Driver for JDK 1.2 and 1.3, Hibernate version 3.2.6.ga, connection池库 C3P0 版本 0.9.1。

更新:感谢@BalusC 澄清确实是 Hibernate 执行了查询,现在我对发生的事情有了更好的了解。我将解释我们处理休眠会话的方式(这是非常基本的,是的,如果您有关于如何更好地处理它的建议,我们非常欢迎!)

我们有一个过滤器(实现 javax.servlet.Filter),它在启动时(init 方法)构造会话工厂(可能这只发生一次)。然后进入应用程序的每个 HttpRequest 都会通过过滤器并获得一个会话并启动一个事务。当进程结束时,它通过过滤器返回,提交事务,终止休眠会话,然后继续前进页面(我们不将休眠会话存储在 Http 会话中,因为它在我们的测试)。

现在到了我认为问题所在的部分。在我们的开发环境中,我们在 Tomcat 5.5 中部署我们的应用程序,当我们启动服务时,所有过滤器都会立即启动,并且只启动一次。在使用 OC4J 的生产环境中似乎不是这样工作的。我们部署应用程序,只有当第一个请求到达时,OC4J 才会实例化过滤器。

这使我认为 OC4J 在每个请求上实例化过滤器(或至少多次,这仍然是错误的),从而在每个请求上创建一个会话工厂,执行该 %&%#%$# 查询,这导致我的问题!

现在,这是正确的吗?有没有办法让我配置 OC4J 让它只实例化一次过滤器?

非常感谢大家抽出时间来回复这个问题!

4

9 回答 9

3

它确实来自 Hibernate,特别是org.hibernate.tool.hbm2ddl.TableMetadata. 它在每个都用于验证架构(表和列映射)。显然,它不必要地在每个产生的请求或会话上执行,而不是在应用程序启动期间只执行一次。例如,您不是在每个请求或会话上都不必要地调用 Hibernate Configurator 吗?

于 2010-04-14T22:34:58.140 回答
2

正如@BalusC所指出的,此查询是在模式验证期间执行的。SessionFactory但是验证通常在创建(如果激活)时一劳永逸地完成。您是否明确调用以下方法:Configuration#validateSchema(Dialect, DatabaseMetadata)


现在,这是正确的吗?有没有办法让我配置 OC4J 让它只实例化一次过滤器?

您对 Open Session In View 的实现看起来不错(并且非常接近此页面中建议的实现)。并且根据 Servlet 规范,每个容器的 Java 虚拟机 (JVMTM) 仅实例化部署描述符中的每个声明一个实例<filter>。由于 OC4J 不太可能不是这种情况,我很想说肯定还有其他东西。

您可以在过滤器中添加一些日志记录吗?制作SessionFactory静态(在一个好的旧HibernateUtil类中)怎么样?

于 2010-04-14T23:13:00.103 回答
2

好吧,经过几个月的研究,事实证明问题不是我的 Web 应用程序。问题在于使用相同数据库实例(不同用户)的其他 Oracle Forms 应用程序。

发生的事情是 Oracle Forms 应用程序锁定了数据库上的记录,因此使数据库的几乎所有工作都变得非常缓慢(包括我心爱的 Hibernate 查询)。

锁定的原因是 Oracle Forms 应用程序的所有外键都没有被索引。因此,正如我的老板向我解释的那样(他发现了原因),当用户在 Oracle Form 应用程序中编辑主从关系的主记录时,如果没有外键索引,数据库会锁定整个明细表. 这是因为 Oracle Forms 的工作方式是更新主记录的所有字段,包括主键字段,即外键引用的字段。

简而言之,请永远不要让你的外键没有索引。我们为此受了很多苦。

感谢所有花时间提供帮助的人。

于 2010-07-28T13:55:24.493 回答
2

具体来说,编写支持不同数据库的软件的人会以数据库中立的方式打包他们的软件。IE。当不存在覆盖时,他们所做的是使用 jdbc db metadata getTables 调用来检查连接是否仍然有效。通常,您使用 select * from dual 等进行覆盖,但是如果没有这样做,或者您没有具体说明您使用的是哪种数据库,该软件被编写为运行可以与任何 JDBC 驱动程序一起使用的东西。jdbc db metadatabase getTables 将执行此操作。

于 2011-10-05T19:25:57.197 回答
2

我只是想提出我用来解决这个问题的解决方法。我们的数据库中通常有很多模式,这需要几个小时才能在我们尝试使用的应用程序中完成这么多)。

我所做的是覆盖正在连接的架构中的 ALL_OBJECTS 视图,以便它只带回它自己的对象,而不是数据库中的所有对象。

例如

创建或替换视图 ALL_OBJECTS 作为 SELECT USER OWNER,O.* FROM USER_OBJECTS O;

这不是最好的解决方案,但对于这个应用程序来说,没有其他东西可以使用 ALL_OBJECTS 视图,因此它工作正常并且启动速度大大加快。

于 2012-07-12T14:51:48.273 回答
1

您的 10g 数据库中的 sys 模式是否使用更新的统计数据进行分析?您是否收集了 sys 模式中固定表的统计信息。对 all_objects 的查询不应该对系统造成太大负担。如果您通过 autotrace/tkprof 运行查询,那么主要的资源花费在哪里/在哪里。

于 2010-04-13T19:18:11.173 回答
1

这来自默认的 C3PO 测试查询。在您的配置中提供一个更简单的查询。比如,从双重中选择“X”。

于 2010-06-04T21:50:08.707 回答
1

有同样的问题,原因正是 Bob Breitling 所描述的,C3P0 默认使用 JDBC API 进行连接测试:

java.sql.DatabaseMetaData#getTables(....)

为了改变这种行为,preferredTestQuery必须被设置,或者如果 C3P0 通过休眠使用 - hibernate.c3p0.preferredTestQuery

于 2013-07-10T14:48:56.303 回答
0

我相信这个查询来自 Oracle JDBC 驱动程序,以实现通过 DatabaseMetaData 检索数据库对象信息的 Hibernate 请求。

这个查询不应该太昂贵,或者至少不在我方便的系统上。您对 all_objects 的计数是多少,更重要的是,您在解释计划的行/字节总数中看到了什么?

于 2010-04-13T15:53:39.227 回答