我正在开发一个由 Maven 模块组成的 Java EE 7 EAR 应用程序。它对 LAN 上另一台服务器上的 Oracle 11 数据库进行数据库调用。我正在部署到在 Ubuntu 12.04 上运行的 Glassfish 4.0.1-b03。我刚刚从 Oracle 下载了最新的 OJDBC6.jar。根据http://docs.oracle.com/cd/E18930_01/html/821-2418/gbxjh.html我把 ojdbc6.jar 放在domain1/lib/ext
.
使用 SQLDeveloper 并使用几乎相同的查询来查询数据库需要 10 毫秒。通过 JPA/JPQL 进行相同的查询需要 0.5 到 3 分钟,具体取决于配置,我试图将其降低到更合理的程度。
该查询返回 40 行,因此分页无济于事。
我使用 Wireshark 来监控返回的数据,所花费的时间都在数据库上。问题必须在于正在发送的查询。
我使用以下命令打开了日志记录,并显示了我认为 EclipseLink 正在发送到数据库的查询:
<property name="eclipselink.logging.level" value="FINEST" />
<property name="eclipselink.logging.level.sql" value="FINEST" />
配置 1
persistence.xml 包含:
<property name="eclipselink.target-database" value="Oracle"/>
在日志中查询:
SELECT ALERT_P, CNT, COLOUR, DFROMUIDCNT, FROMUIDCNT, IS_PRIORITYWORD, IS_STOPWORD, N, NIJ, NRTCNT, PJ, RTCCNT, RTCNT, TIME_STAMP, STEM, TWEETS FROM ALL_ALERTS WHERE (TIME_STAMP BETWEEN ? AND ?) ORDER BY TIME_STAMP, STEM
耗时 25 秒
配置 2
更改 persistence.xml 以包含:
<property name="eclipselink.target-database" value="Oracle11"/>
有一个例外:
org.glassfish.deployment.common.DeploymentException: java.lang.NoSuchFieldError: HINT
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:765)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getAbstractSession(EntityManagerFactoryDelegate.java:204)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:304)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:336)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:302)
at org.glassfish.persistence.jpa.JPADeployer$2.visitPUD(JPADeployer.java:451)
at org.glassfish.persistence.jpa.JPADeployer$PersistenceUnitDescriptorIterator.iteratePUDs(JPADeployer.java:510)
at org.glassfish.persistence.jpa.JPADeployer.iterateInitializedPUsAtApplicationPrepare(JPADeployer.java:492)
at org.glassfish.persistence.jpa.JPADeployer.event(JPADeployer.java:395)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:131)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:484)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:539)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:535)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:356)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:534)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:565)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:557)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:356)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:556)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1464)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:109)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1846)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1722)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:534)
at com.sun.enterprise.v3.admin.AdminAdapter.onMissingResource(AdminAdapter.java:224)
at org.glassfish.grizzly.http.server.StaticHttpHandlerBase.service(StaticHttpHandlerBase.java:189)
at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:496)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:175)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:187)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:837)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
at java.lang.Thread.run(Thread.java:722)
根据http://en.wikibooks.org/wiki/Java_Persistence/Oracle应该使用 Oracle11。我不知道为什么我会得到这个例外。 对这个问题有什么想法吗?
配置 3
eclipselink.target-database
从persistence.xml 中删除。
查询是:
SELECT ALERT_P, CNT, COLOUR, DFROMUIDCNT, FROMUIDCNT, IS_PRIORITYWORD, IS_STOPWORD, N, NIJ, NRTCNT, PJ, RTCCNT, RTCNT, TIME_STAMP, STEM, TWEETS FROM ALL_ALERTS WHERE (TIME_STAMP BETWEEN ? AND ?) ORDER BY TIME_STAMP, STEM
哦,它和上面一样,所以显然这不是发送给 Oracle 的。
耗时:2.5分钟。
所以 EclipseLink 属性很有帮助,但如果我能做到这一点,也许“Oracle11”的价值会更好。
配置 4
与配置 3相同,但我删除了ORDER BY TIMESTAMP, STEM
.
耗时:1.5分钟。
配置 5
与配置 1相同,但我删除了ORDER BY TIMESTAMP, STEM
.
耗时:25 秒。
配置 6
我恢复了ORDER BY
并将ojdbc6.jar
from移动lib/ext
到lib/
。
耗时:26 秒。
配置 7
与配置 6相同,但更改eclipselink.target-database
为Oracle11
,这次错误是:
org.glassfish.deployment.common.DeploymentException: java.lang.NoClassDefFoundError: oracle/sql/TIMESTAMP
验证 wiki 页面是否正确,jar 需要在ext
其中获取特定于 Oracle 的扩展。
在我看来,问题在于发送到 Oracle 的查询没有针对它进行优化。
谁能告诉我:
- 使用“Oracle11”时的异常是什么(当罐子在时
ext/
)? - 有没有其他方法可以针对 Oracle 优化查询?
接下来我将尝试一个@NamedNativeQuery
,看看我是否可以使用相同的查询。SQLDeveloper。尽管查询并不复杂,但我看不出这会改善 JPA 的功能。该查询是:
select * from all_alerts t1 WHERE t1.time_stamp between to_date('2013-01-22 16:00:00','YYYY-MM-DD HH24:MI:SS') and to_date('2013-01-22 16:05:00','YYYY-MM-DD HH24:MI:SS') ORDER BY t1.time_stamp, t1.stem;
实际上,我首先要确保我在 JPQL 查询中发送的日期格式相同。
任何意见或反馈表示赞赏。
更新
现在,我之前忘记添加一些有趣的东西。以下@NamedQuery
在预期时间内运行(一次查询为 0.086 秒)。
@NamedQuery(name = "AllAlert.findLatestAlerts", query = "SELECT a FROM AllAlert a WHERE a.id.timeStamp in"
+ " (SELECT MAX(a.id.timeStamp) from AllAlert AS a) ORDER BY a.id.stem"),
这对我来说似乎更复杂。