Как избежать этого очень тяжелого запроса, который замедляет работу приложения? - PullRequest
5 голосов
/ 13 апреля 2010

У нас есть веб-приложение, работающее в производственной среде, и в какой-то момент клиент пожаловался на то, насколько медленно оно работает.

Когда мы проверили, что происходит с приложением и базой данных, мы обнаружили этот «драгоценный» запрос, который выполнялся несколькими пользователями одновременно (таким образом, создавая чрезвычайно высокую нагрузку на сервер базы данных):

SELECT   NULL AS table_cat,
         o.owner AS table_schem,
         o.object_name AS table_name,
         o.object_type AS table_type,
         NULL AS remarks
FROM     all_objects o
WHERE    o.owner LIKE :1 ESCAPE :"SYS_B_0" AND
         o.object_name LIKE :2 ESCAPE :"SYS_B_1" AND
         o.object_type IN(:"SYS_B_2", :"SYS_B_3")
ORDER BY table_type, table_schem, table_name

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

Информация об окружающей среде: Red Hat Enterprise Linux 5.3 (Tikanga), JDK 1.5, веб-контейнер OC4J (с сервером приложений Oracle), Oracle Database 10.1.0.4, драйвер JDBC для JDK 1.2 и 1.3, Hibernate версия 3.2.6. ga, библиотека пула соединений C3P0 версия 0.9.1.

ОБНОВЛЕНИЕ : Спасибо @BalusC за разъяснение того, что действительно Hibernate выполняет запрос, теперь у меня есть лучшее представление о том, что происходит. Я объясню, как мы справляемся с Hibernate-сессией (это очень элементарно, да, если у вас есть предложения о том, как справиться с этим лучше, они более чем приветствуются!)

У нас есть фильтр (реализующий javax.servlet.Filter), который при запуске (метод init) создает фабрику сессий (возможно, это происходит только один раз). Затем каждый запрос HttpRequest, который поступает в приложение, проходит через фильтр, получает новый сеанс и запускает транзакцию. Когда процесс завершен, он возвращается через фильтр, делает фиксацию транзакции, убивает сеанс гибернации, затем переходит на страницу пересылки (мы не сохраняем сеанс гибернации в сеансе Http потому что он никогда не работал хорошо в наших тестах).

Теперь наступает момент, когда я думаю, что проблема в этом. В нашей среде разработки мы разворачиваем наши приложения в Tomcat 5.5, и при запуске службы все фильтры запускаются сразу и только один раз . В производственной среде с OC4J, похоже, не работает таким образом. Мы разворачиваем приложение и только при поступлении первого запроса OC4J создает фильтры.

Это наводит меня на мысль, что OC4J создает фильтры для каждого запроса (или, по крайней мере, несколько раз, что все еще неправильно), создавая таким образом фабрику сеансов для каждого запроса, который выполняет этот% &% #% $ # запрос, который приводит к моей проблеме!

Теперь это правильно? У меня есть способ настроить OC4J, чтобы он создавал фильтры только один раз?

Большое спасибо всем, что нашли время ответить на это!

Ответы [ 9 ]

3 голосов
/ 15 апреля 2010

Это действительно из Hibernate и, в частности, org.hibernate.tool.hbm2ddl.TableMetadata. Каждый из них использовался для проверки схемы (отображение таблицы и столбца). По-видимому, это было излишне выполнено для каждого порожденного запроса или сеанса, а не только один раз при запуске приложения. Например, не нужно ли вам без необходимости вызывать Hibernate Configurator при каждом запросе или сеансе?

2 голосов
/ 12 июля 2012

Я просто хотел использовать обходной путь, который я использовал, чтобы обойти эту проблему. У нас обычно есть много схем в наших базах данных, и это заняло бы часы, чтобы закончить в приложении, которое мы пытались использовать, которое использовало hibernate из-за большого количества объектов, которые он закончил проверять (сам запрос выполнялся быстро, но он просто выполнял их так много).

Я переопределил представление ALL_OBJECTS в схеме, к которой он подключен, и теперь он возвращает только свои собственные объекты, а не все объекты в БД.

, например

СОЗДАТЬ ИЛИ ЗАМЕНИТЬ ПОСМОТРЕТЬ ВСЕ_ОБЪЕКТЫ, КАК ВЫБРАТЬ ВЛАДЕЛЬЦА ПОЛЬЗОВАТЕЛЯ, O. * ОТ USER_OBJECTS O;

Это не самое лучшее решение, но для этого приложения нет ничего другого, что могло бы использовать представление ALL_OBJECTS, поэтому оно отлично работает и запускается значительно быстрее.

2 голосов
/ 05 октября 2011

В частности, люди, которые пишут программное обеспечение, поддерживающее различные базы данных, упаковывают свое программное обеспечение нейтральным образом. то есть. когда нет переопределения, то они используют вызов метаданных jdbc db getTables, чтобы проверить, всё ли соединение действительно. Обычно вы переопределяете с помощью select * from dual и т. Д., Но когда это не сделано или вы не указали конкретно, какую базу данных вы используете, программа написана для запуска чего-либо, что будет работать с любым драйвером JDBC. Это сделает база метаданных jdbc getTables.

2 голосов
/ 28 июля 2010

Ладно, после нескольких месяцев, проведенных в поиске, оказалось, что проблема не в моем веб-приложении. Проблема заключалась в том, что другие приложения Oracle Forms использовали один и тот же экземпляр (другого пользователя) базы данных.

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

Причиной блокировок было то, что ни один из внешних ключей приложений Oracle Forms не был проиндексирован. Поэтому, как мой начальник объяснил мне (он обнаружил причину), когда пользователь редактирует основную запись отношения мастер-детали в приложении Oracle Form, база данных блокирует всю таблицу детализации , если есть нет индекса для его внешнего ключа. Это связано с тем, что Oracle Forms работает так, что он обновляет все поля основной записи, включая поля первичного ключа, которые являются полями, на которые ссылается внешний ключ.

Короче, пожалуйста, НИКОГДА не оставляйте свои внешние ключи без индексов . Мы сильно пострадали с этим.

Спасибо всем, кто нашел время, чтобы помочь.

2 голосов
/ 15 апреля 2010

Как указано @ BalusC , этот запрос выполняется во время проверки схемы. Но проверка обычно выполняется один раз для всех при создании SessionFactory (если активирована). Вы явно вызываете следующий метод: Configuration#validateSchema(Dialect, DatabaseMetadata)?


Теперь это правильно? У меня есть способ настроить OC4J, чтобы он создавал фильтры только один раз?

Ваша реализация Open Session In View выглядит хорошо (и очень близка к той, которая предложена в на этой странице ). И в соответствии со спецификацией сервлета только один экземпляр для объявления <filter> в дескрипторе развертывания создается для виртуальной машины Java (JVMTM) контейнера . Поскольку маловероятно, что это не относится к OC4J, я испытываю желание сказать, что должно быть что-то еще.

Можете ли вы добавить запись в фильтр? Как насчет создания SessionFactory статического (в старом добром HibernateUtil классе)?

1 голос
/ 10 июля 2013

Если бы возникла та же проблема, причиной была именно та, которая описана Бобом Брейтлингом, C3P0 по умолчанию использует JDBC API для тестирования соединения:

java.sql.DatabaseMetaData#getTables(....)

Чтобы изменить это поведение, должен быть установлен предпочитаемый тест , или, если C3P0 используется через hibernate - hibernate.c3p0.preferredTestQuery

1 голос
/ 05 июня 2010

Это исходит из тестового запроса C3PO по умолчанию. Укажите более простой запрос в вашей конфигурации. Что-то вроде, выберите «X» из двойного.

1 голос
/ 13 апреля 2010

Анализирует ли схема sys в вашей базе данных 10g обновленную статистику? Вы собрали статистику по фиксированным таблицам в схеме sys. Запросы для всех_объектов не должны обременять систему. Если вы запустите запрос через autotrace / tkprof, на что / где будут потрачены основные ресурсы.

0 голосов
/ 13 апреля 2010

Я полагаю, что этот запрос исходит от драйвера JDBC Oracle для реализации запроса Hibernate для получения информации об объекте базы данных через DatabaseMetaData.

Этот запрос не должен быть слишком дорогим или, по крайней мере, не в системе, которая мне удобна. Каково ваше количество всех_объектов и, что более важно, что вы видите в общем количестве строк / байтов для плана объяснения?

...