Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 准备语句的JPA(Hibernate)本机查询速度慢_Java_Sql_Hibernate_Jpa_Prepared Statement - Fatal编程技术网

Java 准备语句的JPA(Hibernate)本机查询速度慢

Java 准备语句的JPA(Hibernate)本机查询速度慢,java,sql,hibernate,jpa,prepared-statement,Java,Sql,Hibernate,Jpa,Prepared Statement,在JPA后面使用Hibernate 3.3.2GA(以及JBoss5中包含的其他Hibernate软件包)会出现奇怪的性能问题 我正在使用本机查询,并将SQL组装到一个准备好的语句中 EntityManager em = getEntityManager(MY_DS); final Query query = em.createNativeQuery(fullSql, entity.getClass()); SQL有很多连接,但实际上非常基本,只有一个参数。比如: SELECT field1,

在JPA后面使用Hibernate 3.3.2GA(以及JBoss5中包含的其他Hibernate软件包)会出现奇怪的性能问题

我正在使用本机查询,并将SQL组装到一个准备好的语句中

EntityManager em = getEntityManager(MY_DS);
final Query query = em.createNativeQuery(fullSql, entity.getClass());
SQL有很多连接,但实际上非常基本,只有一个参数。比如:

SELECT field1, field2, field3 FROM entity left join entity2 on... left join entity3 on
WHERE stringId like ?
查询在MSSQL Studio上运行不到一秒钟

如果我加上

query.setParameter(0, "ABC123%");
查询将暂停9秒

2012-01-20 14:36:21 - TRACE: - AbstractBatcher.getPreparedStatement:(484) | preparing statement
2012-01-20 14:36:21 - TRACE: - StringType.nullSafeSet:(133) | binding 'ABC123%' to parameter: 1
2012-01-20 14:36:30 - DEBUG: - AbstractBatcher.logOpenResults:(382) | about to open ResultSet (open ResultSets: 0, globally: 0)
但是,如果我只是用值替换“?”(使其不是一个准备好的语句,而是一个直接的SQL查询)

fullSql = fullSql.replace("?", "'ABC123%'");
查询将在不到一秒钟内完成

我真的希望我们准备一个语句(参数的输入是从用户数据中提取的),以防止注入攻击

追溯代码中的慢点,我深入到了jtds-1.2.2包中。令人不快的一行似乎是SharedSocket第841行“getIn().readfull(hdrBuf);”虽然没有什么明显的东西

private byte[] readPacket(byte buffer[])
        throws IOException {
    //
    // Read rest of header
    try {
        getIn().readFully(hdrBuf);
    } catch (EOFException e) {
        throw new IOException("DB server closed connection.");
    }
通过这个堆栈到达

  at net.sourceforge.jtds.jdbc.SharedSocket.readPacket(SharedSocket.java:841)
  at net.sourceforge.jtds.jdbc.SharedSocket.getNetPacket(SharedSocket.java:722)
  at net.sourceforge.jtds.jdbc.ResponseStream.getPacket(ResponseStream.java:466)
  at net.sourceforge.jtds.jdbc.ResponseStream.read(ResponseStream.java:103)
  at net.sourceforge.jtds.jdbc.ResponseStream.peek(ResponseStream.java:88)
  at net.sourceforge.jtds.jdbc.TdsCore.wait(TdsCore.java:3928)
  at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java:1045)
  at net.sourceforge.jtds.jdbc.TdsCore.microsoftPrepare(TdsCore.java:1178)
  at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareSQL(ConnectionJDBC2.java:657)
  at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java:776)
  at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
  at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
  at org.hibernate.loader.Loader.doQuery(Loader.java:697)
  at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
  at org.hibernate.loader.Loader.doList(Loader.java:2228)
  at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125)
  at org.hibernate.loader.Loader.list(Loader.java:2120)
  at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:312)
  at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1722)
  at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:165)
  at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:175)
  at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:67)

检查SQL server正在生成的查询计划。准备好的语句可能特别有问题

让我解释一下

如果您这样做:

SELECT field1, field2, field3 FROM entity left join entity2 on... left join entity3 on
WHERE stringId like 'ABC123%';
SELECT field1, field2, field3 FROM entity left join entity2 on... left join entity3 on
WHERE stringId like ?;
您在“stringId”上有一个索引,SQL server知道它可以使用它

但是,如果您这样做:

SELECT field1, field2, field3 FROM entity left join entity2 on... left join entity3 on
WHERE stringId like 'ABC123%';
SELECT field1, field2, field3 FROM entity left join entity2 on... left join entity3 on
WHERE stringId like ?;

SQL server在创建准备好的语句时不知道它可以使用索引(因为您可以用“%ABC123%”而不是“ABC123%”来填充参数),因此可能会选择完全不同的查询计划。

我将在这里留下这个问题并回答,以防将来有人遇到同样的问题

问题在于JTDS驱动程序将参数字符串发送到MSSQL的方式。显然,Java会在默认情况下尝试发送Unicode参数,MSSQL会将其转换为Ascii。我不知道为什么这需要9秒钟

这里有很多关于这方面的参考资料,但在我能够确定这是驱动程序到MSSQL连接的问题之前,没有任何帮助

这个链接很有帮助:

[http://server.pramati.com/blog/2010/06/02/perfissues-jdbcdrivers-mssqlserver/]

这是使用Microsoft驱动程序的字符串

jdbc:sqlserver://localhost\SQLEXPRESS;
  DatabaseName=TESTDB;
  sendStringParametersAsUnicode=false

您只需将sendStringParametersAsUnicode=false传递给驱动程序URL设置,就可以了。

这是另一个解决方案,适用于可能使用Oracle的用户,他们可能会遇到类似的Unicode问题

检查以确保没有人设置属性oracle.jdbc.defaultNChar=true


有时这样做是为了解决unicode问题,但这意味着所有列都被视为NVARCHAR。如果您在varchar列上有索引,则不会使用该索引,因为oracle必须使用函数来转换字符编码。

让我将jtds-1.2.2添加到技术堆栈中。我已通过Hibernate将其调试到JTDStried jtds-1.2.4中,但是没有乐趣…切换到com.microsoft.sqlserver.jdbc.SQLServerDriver实际上会产生相同的结果…需要看看SQL Server,可能会有一些东西…谢谢Gareth。你说的是100%正确。在这种情况下,主要问题是驱动程序MSSQL连接。我认为MSSQL可能会缓存查询计划,实际上只有SP的可能迭代次数很少,针对一对多关系使用不同的子查询。解决该问题后,47秒内返回100个查询,每个查询超过9秒,这是一个巨大的改进!有解决方案吗?它需要9秒,因为它不会将参数转换为ascii(因为这样可能会丢失数据)。在与参数进行比较之前,它会将每个列的值更改为unicode。这意味着它无法充分利用字段“stringId”上的任何索引,从而导致性能大大降低(我相信我过去也遇到过类似的问题).BTW,我很高兴你解决了你的问题。谢谢你提供的信息,我认为是休眠导致了问题