Многие предприятия полагаются на базу данных Oracle для своего уровня данных. Хотя лицензии стоят дорого, Oracle предоставляет проверенный продукт с точки зрения производительности и масштабируемости, а также очень хорошую поддержку, так что это оказывается хорошим компромиссом. Тем не менее, каждый продукт будет иметь определенные ограничения. Если Oracle используется для обслуживания данных загруженными приложениями, количество параллельных подключений к базе данных часто будет причиной узких мест. Большое число может привести к высокой загрузке ЦП на стороне Oracle. Кроме того, это может лишить другие приложения доступа к соединениям и привести к функциональным проблемам. Таким образом, для разработчиков становится критически важным понимать не только количество подключений, потребляемых их приложениями, но и то, насколько эффективно они используются.

Прежде чем мы углубимся, есть одно предварительное условие для работы приведенного ниже анализа. Нам нужно убедиться, что для атрибута модуля установлено соответствующее значение. Один из способов сделать это — при создании соединения. Приложение может установить для атрибута initSql значение call dbms_application_info.set_module('<module-name>','<action-name>') . Это поможет нам сопоставить соединение с базой данных с определенным приложением при просмотре базы данных оракула.

Все установленные соединения с базой данных

Переходя к запросам, мы можем получить основную информацию из представлений «gv$session» и «gv$sql». Представление «gv$session» может предоставить нам как активные, так и неактивные соединения. Если мы отлаживаем производительность нашего конкретного приложения, мы можем настроить остальное и добавить предложение where для атрибута модуля.

select status, count(1) 
from gv$session
where module = '<module-name>' 
and type = 'USER' 
group by status;

Все активные соединения

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

  1. Запрос работает с большим объемом данных, поступающих из нескольких таблиц.
  2. Код не использует оптимизированный набор запросов для достижения функциональности. Например, если у нас есть метод для вставки одной записи, и если кто-то подумал о повторном использовании этого метода, вызвав его в цикле, он будет работать нормально для небольших данных, но займет много времени для больших данных.
  3. Это подключение заблокировано от выполнения необходимых вставок или обновлений другим подключением.

Мы можем увидеть все активные в настоящее время соединения с помощью приведенного ниже запроса. Значение в столбце last_call_et указывает, как долго работает это соединение (в секундах). В случае 1 и 2 мы можем продолжить отладку, взяв sql_id и изучив код или количество данных, присутствующих в этих таблицах. В случае 3 другие атрибуты event, blocking_instance, blocking_session, seconds_in_wait дадут больше информации о том, какой другой сеанс блокирует его и сколько времени прошло в ожидании.

select last_call_et, module, sql_id, event, blocking_instance, blocking_session, seconds_in_wait 
from gv$session
where module = '<module-name>' 
and type = 'USER' 
and status = 'ACTIVE' 
order by last_call_et desc, module, sql_id, event, blocking_instance, blocking_session, seconds_in_wait;
select * from gv$sql where sql_id = '<above-sql-id>';

Все неактивные соединения

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

select last_call_et, module, prev_sql_id  
from gv$session 
where module = '<module-name>' 
and type = 'USER' 
and status = 'INACTIVE';

select * from gv$sql where sql_id = '<above-prev-sql-id>';

Примечания:

  1. Стандартными представлениями для проверки производительности базы данных являются v$session, v$sql и другие. Представления «v$» хорошо работают, если база данных размещена на одном узле. Однако, если база данных разделена на несколько узлов, нам нужно посмотреть на представления «gv$». Столбец «INST_ID» сообщит нам, какой именно узел выполняет запрос.
  2. Интерпретация значения last_call_et зависит от значения gv$sql_plan.optimizer . Значение по умолчанию — «ALL_ROWS», но его можно изменить. В случае «ALL_ROWS» last_call_et будет отражать общее время, прошедшее для этого вызова. Однако, если мы используем «FIRST_ROWS» или «FIRST_ROWS_N», это значение будет представлять прошедшее время только для количества строк, возвращаемых в каждой операции.

Это поможет нам понять причину нагрузки с точки зрения базы данных. Чтобы понять, как отлаживать нагрузку с точки зрения приложения, нам нужно взглянуть на свойства подключения к пулу базы данных. Пожалуйста, обратитесь к другой моей статье — https://diwakargrandhi.medium.com/understanding-the-database-connection-pool-dbcp-properties-ae0747f0962b. Спасибо.