apache derby зависает при выполнении запроса

#sql #derby

#sql #derby

Вопрос:

я был бы очень признателен за помощь здесь. Я получил эту базу данных derby от моего клиента и их приложения на основе гибернации. Я не могу заставить его работать, потому что Hibernate генерирует запрос, который отключает всю базу данных:

 select houses0_.STREET_ID as STREET5_1_, houses0_.ID as ID1_, houses0_.ID as ID42_0_, houses0_.NAME as NAME42_0_, houses0_.SHORT_NAME as SHORT3_42_0_, houses0_.INDEX as INDEX42_0_ from SRG.HOUSE_REFERENCE houses0_ where houses0_.STREET_ID in (select streets0_.ID from SRG.STREET_REFERENCE streets0_ where streets0_.TOWNSHIP_ID in (select townships0_.ID from SRG.TOWNSHIP_REFERENCE townships0_ where townships0_.CITY_ID='555'))
 

Я не вижу в этом ничего подозрительного, но когда я запускаю derby с его помощью — derby просто ничего не делает. Вот мои журналы:

  2011-10-31 21:58:10.328 GMT Thread[DRDAConnThread_3,5,main] (XID = 1152939), (SESSIONID = 1), (DATABASE = dev), (DRDAID = NF000001.FC97-434877518919679629{1}), Begin compiling prepared statement: select houses0_.STREET_ID as STREET5_1_, houses0_.ID as ID1_, houses0_.ID as ID42_0_, houses0_.NAME as NAME42_0_, houses0_.SHORT_NAME as SHORT3_42_0_, houses0_.INDEX as INDEX42_0_ from HOUSE_REFERENCE houses0_ where houses0_.STREET_ID in (select streets0_.ID from STREET_REFERENCE streets0_ where streets0_.TOWNSHIP_ID in (select townships0_.ID from TOWNSHIP_REFERENCE townships0_ where townships0_.CITY_ID='555')) :End prepared statement
2011-10-31 21:58:10.682 GMT Thread[DRDAConnThread_3,5,main] (XID = 1152939), (SESSIONID = 1), (DATABASE = dev), (DRDAID = NF000001.FC97-434877518919679629{1}), End compiling prepared statement: select houses0_.STREET_ID as STREET5_1_, houses0_.ID as ID1_, houses0_.ID as ID42_0_, houses0_.NAME as NAME42_0_, houses0_.SHORT_NAME as SHORT3_42_0_, houses0_.INDEX as INDEX42_0_ from SRG.HOUSE_REFERENCE houses0_ where houses0_.STREET_ID in (select streets0_.ID from SRG.STREET_REFERENCE streets0_ where streets0_.TOWNSHIP_ID in (select townships0_.ID from SRG.TOWNSHIP_REFERENCE townships0_ where townships0_.CITY_ID='555')) :End prepared statement
2011-10-31 21:58:10.758 GMT Thread[DRDAConnThread_3,5,main] (XID = 1152939), (SESSIONID = 1), (DATABASE = dev), (DRDAID = NF000001.FC97-434877518919679629{1}), Executing prepared statement: select houses0_.STREET_ID as STREET5_1_, houses0_.ID as ID1_, houses0_.ID as ID42_0_, houses0_.NAME as NAME42_0_, houses0_.SHORT_NAME as SHORT3_42_0_, houses0_.INDEX as INDEX42_0_ from SRG.HOUSE_REFERENCE houses0_ where houses0_.STREET_ID in (select streets0_.ID from SRG.STREET_REFERENCE streets0_ where streets0_.TOWNSHIP_ID in (select townships0_.ID from SRG.TOWNSHIP_REFERENCE townships0_ where townships0_.CITY_ID='555')) :End prepared statement
 

И после этого НИЧЕГО.
Я установил некоторые свойства:

 derby.drda.portNumber=1529

derby.locks.deadlockTrace=true
derby.locks.monitor=true

derby.locks.deadlockTimeout=1
derby.locks.waitTimeout=1

derby.language.logStatementText=false
derby.infolog.append=true

derby.stream.error.logSeverityLevel=0

derby.drda.logConnections=true

derby.language.logStatementText=true

derby.language.logQueryPlan=true
 

чтобы увидеть, что происходит, но в журналах ничего нет, выполнение этого запроса занимает целую вечность, либо оно выполняется из hibernate, либо squirrelsql, либо из инструмента ij от derby.
Как вы можете видеть, тайм-ауты довольно малы, но derby не останавливает выполнение запроса, он оставляет его делать все, что хочет запрос.

Запрос не такой сложный — я переписал его с помощью joins, и для выполнения потребовалось 1 сек. Но не в такой форме — я не понимаю, почему? Можете ли вы дать мне какие-либо подсказки?

UPD: house_reference содержит 7508 строк, выбор * из house_reference занимает менее секунды, street_reference содержит ~ 44 тыс. строк, а подзапрос

 select streets0_.ID from STREET_REFERENCE streets0_ where streets0_.TOWNSHIP_ID in (select townships0_.ID from TOWNSHIP_REFERENCE townships0_ where townships0_.CITY_ID='52000001000')
 

возвращает 111 строк менее чем за секунду. таким образом, выбор * из house_reference с предложением in, содержащим 111 строк, занимает 22 минуты и возвращает 0 результатов. Для меня это не выглядит нормально, но я не настолько опытен в администрировании баз данных, чтобы судить, поэтому я спрашиваю сообщество 🙂

Ответ №1:

Запросы, указывающие «in (подзапрос)», не всегда могут быть заменены соответствующим соединением. Этот процесс называется «выравнивание», и существуют правила, которым должна следовать база данных, чтобы дать правильный ответ. Смотрите эту документацию: http://db.apache.org/derby/docs/10.8/tuning/ctuntransform36368.html

К сожалению, нередко возникают значительные проблемы с производительностью при выполнении подзапросов в соединениях. Я рад, что вы нашли обходной путь (при условии, что ваш переписанный запрос на самом деле является приемлемым обходным путем для вас).

Библиотеки объектно-реляционных сопоставлений могут генерировать некоторые сложные запросы. Если вы можете заставить запрос в конечном итоге выполняться, вы можете кое-что узнать из плана запроса.

Другая возможность заключается в том, что статистика базы данных стала неточной, в результате чего Derby выбрал плохой план запроса. В последних версиях Derby улучшена поддержка повторного вычисления статистики, что может помочь оптимизатору выбрать лучший план запроса.

В руководстве по настройке Derby по адресу http://db.apache.org/derby/docs/10.8/tuning/index.html

Комментарии:

1. Это не обходной путь, потому что мне не разрешено изменять эту конкретную часть кода клиента. Я переписал его, просто чтобы проверить, все ли в порядке с таблицами, и они не слишком большие. Я спрашиваю: почему derby не останавливает этот запрос после тайм-аута? почему он не записывает план выполнения в файл журнала? почему derby ничего не делает с этим во время выполнения?

2. Я не уверен. Какой тайм-аут вы имеете в виду? derby.locks.deadlockTimeout и derby.locks.waitTimeout имеют отношение к управлению параллелизмом между независимыми транзакциями, А НЕ к остановке выполнения запроса, выполнение которого занимает много времени.

3. Ох. Это единственные тайм-ауты, которые я установил до сих пор. Это имеет некоторый смысл, но время выполнения действительно огромно.