簡體   English   中英

用於准備語句SLOW的JPA(Hibernate)本機查詢

[英]JPA (Hibernate) Native Query for Prepared Statement SLOW

使用JPA背后的Hibernate 3.3.2GA(以及JBoss 5中包含的其余Hibernate包)存在奇怪的性能問題。

我正在使用Native Query,並將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)

但是,如果我只是替換“?” 使用該值(使其不是Prepared Statement,而只是一個直接的SQL查詢。

fullSql = fullSql.replace("?", "'ABC123%'");

查詢將在不到一秒鍾內完成。

我真的更喜歡我們准備好的聲明(參數的輸入是從用戶數據中提取的)以防止注入攻擊。

追溯代碼中的慢點,我深入到了jtds-1.2.2包中。 違規行似乎是SharedSocket line 841“getIn()。readFully(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)

我會留下這個問題並在這里回答,以防將來有人遇到同樣的問題。

問題在於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設置就可以了。

檢查SQL Server正在生成的查詢計划。 准備好的陳述可能特別成問題。

讓我解釋...

如果你這樣做:

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

並且你有一個索引“stringId”SQL服務器知道它可以使用它。

但是,如果你這樣做:

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

SQL服務器不知道它可以在創建預准備語句時使用索引(因為您可以使用'%ABC123'而不是'ABC123%'填充參數),因此可以選擇完全不同的查詢計划。

對於可能使用類似Unicode問題的Oracle的人來說,另一個答案是......

檢查以確保某人未設置屬性oracle.jdbc.defaultNChar = true

有時這樣做是為了解決unicode問題,但這意味着所有列都被視為nvarchars。 如果varchar列上有索引,則不會使用它,因為oracle必須使用函數來轉換字符編碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM