Intereting Posts
Произошла ошибка базы данных. Номер ошибки: 1054 SQLalchemy указывает, какой индекс использовать (Scala) Преобразование строки в Date в Apache Spark SSRS Gray out Параметр, основанный на результатах других параметров Получение сопоставленных имен столбцов свойств в структуре сущностей Найти все те столбцы, которые имеют только нулевые значения, в таблице MySQL Быстрое обновление данных Access с данными Excel с помощью Excel VBA Если один столбец пуст, извлеките данные с помощью других столбцов, где условие в SQL Server Не удается подключиться к базе данных Azure SQL, даже с использованием белого IP-адреса Был ли исходный SQL написан на сборке или C? Объединение строк Oracle Рассчитать рабочие дни в Oracle SQL (нет функций или процедур) sql с подстрокой специального символа с sqlite Конкатенация значений строк Если я использую классный sql-класс в grails, он использует объединение соединений grails?

JPA (Hibernate) Собственный запрос для подготовленного заявления SLOW

Имея странную производительность с использованием Hibernate 3.3.2GA за JPA (и остальные пакеты Hibernate, включенные в JBoss 5.)

Я использую 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) 

Однако, если я просто заменил «?» со значением (что делает его не подготовленным заявлением, а просто прямым SQL-запросом.

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

запрос будет завершен менее чем за секунду.

Я бы предпочел нам подготовленное заявление (вход для параметров извлекается из пользовательских данных), чтобы предотвратить инъекции.

Отслеживая медленную точку в коде, я прибыл глубоко в пакет jtds-1.2.2. Строкой нарушения является линия SharedSocket 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, переданный в настройку вашего драйвера, и вы хороши.

Проверьте планы запросов, которые производит SQL-сервер. Подготовленные заявления могут быть особенно проблематичными.

Позволь мне объяснить…

Если вы это сделаете:

 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%») и, таким образом, можете выбрать совершенно другой план запроса.

И еще один ответ для людей, потенциально использующих Oracle с аналогичной проблемой Unicode …

Убедитесь, что кто-то не установил свойство oracle.jdbc.defaultNChar = true

Иногда это делается для решения проблем с unicode, но это означает, что все столбцы рассматриваются как nvarchars. Если у вас есть индекс в столбце varchar, он не будет использоваться, потому что oracle должен использовать функцию для преобразования кодировки символов.