Сегодня проверим Dimension-UI на задаче мониторинга истории активных сессий в базах данных Oracle, PostgreSQL, ClickHouse и MS SQL Server в режиме реального времени.

История активных сессий (Active Session History, ASH) — очень удобный способ получения информации о работе БД в кратком виде. Когда важно максимально быстро отследить, что происходит с системой в настоящее время, оценить развитие текущей ситуации — это рабочая активность или начало каких‑либо проблем — в том числе, через быстрый просмотр baselines в недавнем прошлом системы и сравнить их с текущими данными.

Изначально, данный подход был разработан и применен в СУБД Oracle начиная с 10g версии. Архитектурно в Oracle это выглядит как плоская таблица в памяти V$ACTIVE_SESSION_HISTORY, в которую с определенным интервалом (стандартно 1 секунда, но его значение можно изменять) записывается состояние каждой активной сессии: идентификатор сессии, SQL-запроса, процесса операционной системы, текущий статус сессии — в работе или ожидании получения доступа к ресурсу, статистики потребления памяти и проч. Периодически информация из таблицы в памяти сбрасывается на диск в таблицу DBA_HIST_ACTIVE_SESS_HISTORY репозитория рабочей нагрузки AWR.

Архитектура истории активных сессий в СУБД Oracle
Архитектура истории активных сессий в СУБД Oracle

Настройка окружения

Для начала работы нам потребуется установить тестовый стенд с базами данных Oracle, PostgreSQL, ClickHouse и MS SQL Server — я использую Docker. Далее, на клиетской станции установить Java не ниже 24 версии и загрузить Dimension-UI, указать в скрипте запуска run.bat/run.sh путь к установленной Java и далее приступить к настройке сбора данных.

В Dimension-UI данные с удаленных систем можно собирать на клиентской станции, где установлено приложение. Приложение в этом случае работает как агент для сбора данных или же подтягивать изменения из уже сохраненных таблиц на удаленной системе — приложение автоматически отслеживает метку времени и подгружает данные в пакетном режиме в локальную БД. В первом случае в настройках по запросу указываем BY_CLIENT_JDBC, а для второго варианта — BY_SERVER_JDBC. Подробности по настройке приложения есть в документации на Github.

Система позволяет использовать любые запросы для сбора данных или можно взять за основну шаблоны запросов для мониторинга истории активных сессий для Oracle, PostgreSQL, ClickHouse и MS SQL Server — все это описано в документации, повторяться не буду — двигаемся дальше.

Настройки и текст запросов
  • Настройка запроса для сбора данных для Oracle — используем режим BY_SERVER_JDBC, метка времени SAMPLE_TIME.

SELECT * FROM v$active_session_history
  • Настройка запроса для сбора данных для PostgreSQL — используем режим BY_CLIENT_JDBC, метка времени SAMPLE_TIME.

SELECT
    current_timestamp AS SAMPLE_TIME,
    datid,
    datname,
    pid AS SESSION_ID,
    pid AS SESSION_SERIAL,
    usesysid AS USER_ID,
    COALESCE(usename, 'unknown') AS usename,
    CONCAT(application_name, '::', backend_type, '::', COALESCE(client_hostname, client_addr::text, 'localhost')) AS PROGRAM,
    wait_event_type AS WAIT_CLASS,
    wait_event AS EVENT,
    query,
    SUBSTRING(md5(query) FROM 0 FOR 15) AS SQL_ID,
    LEFT(query, STRPOS(query, ' ')) AS SQL_OPNAME,
    COALESCE(query_start, xact_start, backend_start) AS query_start,
    1000 * EXTRACT(EPOCH FROM (clock_timestamp() - COALESCE(query_start, xact_start, backend_start))) AS duration
FROM
    pg_stat_activity
WHERE
    state = 'active'
  • Настройка запроса для сбора данных для ClickHouse — используем режим BY_CLIENT_JDBC, метка времени DT.

SELECT now() as dt, * from system.processes
  • Настройка запроса для сбора данных для MS SQL Server — используем режим BY_CLIENT_JDBC, метка времени DT.

SELECT 
    getdate() as dt,
    s.session_id,
    s.host_name,
    s.program_name,
    s.login_name,
    DB_NAME(s.database_id) AS database_name,
    s.status AS session_status,
    r.status AS request_status,
    r.wait_type,
    r.wait_resource,
    r.wait_time AS wait_time_ms,
    -- Wait classification
    CASE 
        WHEN r.wait_type IS NULL THEN 'No Wait'
        WHEN r.wait_type = '' THEN 'No Wait'
        WHEN r.wait_type IN ('SOS_SCHEDULER_YIELD') THEN 'CPU'
        WHEN r.wait_type IN ('CXPACKET', 'CXCONSUMER') THEN 'Parallelism'
        WHEN r.wait_type LIKE 'LCK%' THEN 'Lock'
        WHEN r.wait_type LIKE 'LATCH%' THEN 'Latch'
        WHEN r.wait_type LIKE 'PAGEIOLATCH%' THEN 'Buffer IO'
        WHEN r.wait_type LIKE 'PAGELATCH%' THEN 'Buffer Latch'
        WHEN r.wait_type IN ('WRITELOG', 'LOGBUFFER', 'LOGMGR') THEN 'Log'
        WHEN r.wait_type LIKE 'ASYNC_NETWORK_IO%' THEN 'Network IO'
        WHEN r.wait_type LIKE 'RESOURCE_SEMAPHORE%' THEN 'Memory'
        ELSE 'Other'
    END AS wait_class,
    r.blocking_session_id,
    r.cpu_time,
    r.total_elapsed_time,
    r.reads,
    r.writes,
    r.logical_reads,
    SUBSTRING(qt.text, 
              CASE WHEN r.statement_start_offset = 0 THEN 1 
                   ELSE r.statement_start_offset/2 + 1 END,
              CASE WHEN r.statement_end_offset = -1 THEN DATALENGTH(qt.text)
                   ELSE (r.statement_end_offset - r.statement_start_offset)/2 
              END) AS executing_query
FROM sys.dm_exec_sessions s
LEFT JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
LEFT JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) qt
WHERE s.is_user_process = 1
    AND s.status <> 'sleeping'
ORDER BY r.wait_time DESC, r.cpu_time DESC;
Настройка детализации

Чтобы при выборе диапазона, в детализации автоматически отображались топы измерений в виде Gantt графиков, их необходимо указать в настройках запроса на вкладке Metadata.

Настройка детализации по измерениям
Настройка детализации по измерениям

После всех настроек, в основном интерфейсе выбираем профиль и запускаем сбор данных — теперь все готово к мониторингу истории активных сессий.

Чтобы было удобно представлять, что из себя представляет пользовательский интерфейс Dimension‑UI — кроме скриншотов будем смотреть основные варианты использования приложения в виде скринкастов.

СУБД Oracle

Для эмуляции нагрузки, выполним сбор статистик в БД и посмотрим на результат в интерфейсе Workspace по измерению WAIT_CLASS.

exec dbms_stats.gather_database_stats();
История активных сессий в БД Oracle - workspace
История активных сессий в БД Oracle - workspace

Выделяем интересующий нас диапазон и смотрим детализацию и топ событий ожиданий по другим измерениям: SESSION_TYPE, EVENT, MODULE etc. В истории активных сессий для 19 версии Oracle измерений больше сотни, поэтому используем быстрый фильтр для выбора измерения EVENT и выполняем фильтрацию по любому произвольно выбранному значению. Фильтры для выбора значений работают по тому же принципу — все быстро и интерактивно.

История активных сессий в БД Oracle
История активных сессий в БД Oracle
История активных сессий в БД Oracle

Если необходимо посмотреть графики всех измерений — запускаем режим Preview и смотрим на все измерения разом в одном интерфейсе — это про многомерный анализ данных временных рядов - писал об этом в статье.

История активных сессий в БД Oracle - preview
История активных сессий в БД Oracle - preview
История активных сессий в БД Oracle - preview

СУБД PostgreSQL

Для эмуляции нагрузки в PostgreSQL запустим pgbench.

pgbench -c 10 -j 2 -t 10000000 postgres

Все тоже самое, и посмотрим на результат в интерфейсе Workspace по измерению WAIT_CLASS.

История активных сессий в БД PostgreSQL - workspace
История активных сессий в БД PostgreSQL - workspace

Посмотрим на топ ожиданий по Program. Это запуск pgbench — ожидаемо. Также попробуем применить фильтры для каждой группы ожиданий и посмотреть распределение данных на временной шкале.

История активных сессий в БД PostgreSQL - workspace
История активных сессий в БД PostgreSQL - workspace
История активных сессий в БД PostgreSQL - workspace

Запускаем режим Preview для PostgreSQL

История активных сессий в БД PostgreSQL — preview
История активных сессий в БД PostgreSQL - preview
История активных сессий в БД PostgreSQL - preview

Аналитическая БД ClickHouse

В данном случае, эмуляции нагрузки делать не будем — просто пронаблюдаем как реагирует БД на наведенные нагрузки от других систем — такой miner's canary. В нашем случае мы запускаем все БД (с подачей нагрузки), мониторинг Dimension-UI на одном хосте с ограничением по памяти (16 Gb), такой стресс тест (а еще браузер Chrome и IDE). В рабочих сценариях так делать, конечно не рекомендуется.

Еще момент — для мониторинга истории активных сессий в ClickHouse используется хранение данных о группах ожиданиях и процессах во вложенных структурах MAP и ARRAY, для этого в backend‑е для Dimension‑UI — Dimension‑DB реализована поддержка сложных типов данных (их хранение, фильтрация по получении данных для основных read API).

Итак, для ClickHouse в интерфейсе Workspace выбираем группы ожиданий по измерению PROFILEVENTS и смотрим результат.

История активных сессий в БД ClickHouse - workspace
История активных сессий в БД ClickHouse - workspace

Проверяем фильтрацию по QUERY_ID — они в тексте в формате UUID.

История активных сессий в БД ClickHouse - workspace
История активных сессий в БД ClickHouse - workspace
История активных сессий в БД ClickHouse - workspace

В режиме Preview для ClickHouse проверим сокрытие всех графиков, выбор и отображение только нужных нам для анализа в текущий момент времени измерений. При необходимости более детального анализа выбираем измерение в Workspace и смотрим топ по времени исполнения запросов — ELAPSED.

История активных сессий в БД ClickHouse - preview
История активных сессий в БД ClickHouse - preview
История активных сессий в БД ClickHouse - preview

СУБД Microsoft SQL Server

Для эмуляции нагрузки в MSSQL создадим тестовую таблицу из sys.objects и выполним на ней аналитический запрос.

Тестовые данные по Microsoft SQL Server
-- Insert test data
INSERT INTO TestLargeTable (ID, Name, Value, Timestamp)
SELECT 
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as ID,
    'Name_' + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as VARCHAR(10)),
    ABS(CHECKSUM(NEWID())) % 1000,
    DATEADD(MINUTE, - (ABS(CHECKSUM(NEWID())) % 525600), GETDATE())
FROM sys.objects s1
CROSS JOIN sys.objects s2
CROSS JOIN sys.objects s3;

-- Verify insertion
SELECT COUNT(*) as TotalRecords FROM TestLargeTable;


WITH TimeWindows AS (
    SELECT 
        t1.ID as ID1,
        t1.Name as Name1,
        t1.Value as Value1,
        t1.Timestamp as Timestamp1,
        t2.ID as ID2,
        t2.Name as Name2,
        t2.Value as Value2,
        t2.Timestamp as Timestamp2,
        DATEDIFF(MINUTE, t1.Timestamp, t2.Timestamp) as TimeDiff,
        ABS(t1.Value - t2.Value) as ValueDiff
    FROM TestLargeTable t1
    CROSS APPLY (
        SELECT TOP 1000 *
        FROM TestLargeTable t2 
        WHERE t2.ID <> t1.ID 
          AND t2.Timestamp BETWEEN DATEADD(HOUR, -24, t1.Timestamp) AND DATEADD(HOUR, 24, t1.Timestamp)
        ORDER BY ABS(t1.Value - t2.Value)
    ) t2
    WHERE t1.Value > 100 AND t2.Value > 100
),
CorrelationAnalysis AS (
    SELECT 
        AVG(Value1) as AvgValue1,
        AVG(Value2) as AvgValue2,
        AVG(Value1 * Value2) as AvgProduct,
        AVG(Value1 * Value1) as AvgSq1,
        AVG(Value2 * Value2) as AvgSq2,
        COUNT(*) as SampleSize,
        (AVG(Value1 * Value2) - AVG(Value1) * AVG(Value2)) / 
        (SQRT(AVG(Value1 * Value1) - AVG(Value1) * AVG(Value1)) * 
         SQRT(AVG(Value2 * Value2) - AVG(Value2) * AVG(Value2))) as PearsonCorrelation
    FROM TimeWindows
)
SELECT 
    *,
    CASE 
        WHEN ABS(PearsonCorrelation) > 0.7 THEN 'Strong Correlation'
        WHEN ABS(PearsonCorrelation) > 0.3 THEN 'Moderate Correlation'
        ELSE 'Weak Correlation'
    END as CorrelationStrength
FROM CorrelationAnalysis;
История активных сессий в БД  Microsoft SQL Server - workspace
История активных сессий в БД Microsoft SQL Server - workspace

Пока не все понятно. Видно что основная активность идет с одного хоста, одна из них по JDBC драйверу, другая из DBeaver. Посмотрим детализацию по выполняемым запросам (в Preview) — и видим что это создание и запись данных в таблицу TestLargeTable и запросы из нее же — просто наводим мышь на графике и видим текст запроса.

История активных сессий в БД Microsoft SQL Server - workspace
История активных сессий в БД  Microsoft SQL Server - workspace
История активных сессий в БД Microsoft SQL Server - workspace
История активных сессий в БД Microsoft SQL Server - preview
История активных сессий в БД  Microsoft SQL Server - preview
История активных сессий в БД Microsoft SQL Server - preview

Информационные панели

Все достаточно просто и понятно, но в Workspace сложно увидеть картинку по всем системам в одном интерфейсе. Для этих целей можно использовать вкладку Dashboard, на которой можно одним взглядом увидеть графики по группам ожиданиям по всем системам. При необходимости перейти на детализацию одним кликом.

История активных сессий - dashboard
История активных сессий - dashboard
История активных сессий — dashboard
История активных сессий - dashboard
История активных сессий - dashboard

Система отчетности

Если есть необходимость оформить результат наблюдения за системами в виде подробного отчета в PDF — для этого можно использовать модуль Report. В интерфейсе Playground выбираем по каким измерениям необходимо получить отчет, сохраняем шаблон дизайна и в интерфейсе Design выбираем диапазоны данных для отображения графиков, детализации и формируем отчет.

История активных сессий - report
История активных сессий - report
История активных сессий — report
История активных сессий - report
История активных сессий — report

AdHoc запросы

Не всегда есть возможность получить все данные и посмотреть их локально — да и не нужно, когда есть возможность напрямую сходить в БД и посмотреть их выполнив запросы. Так это и происходит обычно — выполняем запросы, например в DBeaver и смотрим. Но это неудобно.

В Dimension-UI есть возможность делать это с визуализацией данных временных рядов. Посмотрим сохраненную историю активных сессий в dba_hist_active_sess_history — не выполнив ни одного SQL-запроса.

История активных сессий dba_hist_active_sess_history - adhoc
История активных сессий dba_hist_active_sess_history - adhoc
История активных сессий dba_hist_active_sess_history - adhoc
История активных сессий dba_hist_active_sess_history - adhoc
История активных сессий dba_hist_active_sess_history - adhoc

Заключение

С помощью Dimension‑UI можно быстро анализировать историю активных сессий в различных базах данных и в разных разрезах. Продвинутая система фильтрации позволяет смотреть на данные с разных точек зрения и наблюдать за изменениями с применёнными фильтрами в реальном времени. Это полезно, например, при анализе работы определённого запроса, сессий или любого другого показателя, а также их комбинаций.

Приложение нетребовательно к ресурсам. При тестировании на стенде потребление оперативной памяти в пиковые моменты не превышало 450 МБ. При отображении небольшого количества графиков (десятки) среднее потребление ОЗУ составляет 300–350 МБ.

Разумеется, многое зависит от объёмов данных и частоты обновления графиков. В текущей конфигурации, когда сбор данных для всех БД (кроме ClickHouse) выполняется с интервалом в 3 секунды, для ClickHouse — в 1 секунду, а количество одновременно отображаемых графиков превышает 300, потребление памяти составляет около 400 МБ при использовании Java 25 с такими настройками:

SET JAVA_HOME=C:\PROGRAM FILES\JAVA\jdk-25
SET JAVA_EXE="%JAVA_HOME%\bin\java.exe"
chcp 65001
%JAVA_EXE% -XX:+UseCompactObjectHeaders -XX:+UseZGC -Xmx2024m -DLaF=dark -Dfile.encoding=UTF8 -jar dimension-ui-25.10.2-app.jar

pause

Система работает стабильно, задержек при прокрутке не наблюдается. Единственное, о чём необходимо помнить: для промышленной эксплуатации необходимо выделять для Dimension-UI отдельный хост и не допускать свопинга (использования swap) в системе. Не забывайте использовать ограничения доступа к критичным данным и VDI — это снимает большинство вопросов, связанных с обеспечением безопасности.

Ссылки и дополнительные материалы

  • Репозиторий проекта: Исходный код, инструкции по установке и подробная документация доступны в репозитории на GitHub.

  • О проекте: Dimension UI — это десктопное приложение, предназначенное для сбора, хранения, визуализации и анализа данных временных рядов.

Вроде все, спасибо за внимание!

Комментарии (2)


  1. dreamcp
    09.10.2025 09:51

    Это же просто Prometheus для баз данных! Здорово!
    Если БД находится в загруженном состоянии ~ 1000сессий например, с постоянной высокой нагрузкой, насколько сильно такой мониторинг будет влиять на саму БД?


    1. akardapolov Автор
      09.10.2025 09:51

      Все зависит от самой БД, от среднего размера сохраняемых данных. В Oracle например сбор статистик встроен в ядро, там это происходит очень быстро (прямое чтение данных из спец.структур в памяти, в 10.1 были SQL-запросы). Даже в самых тяжелых ситуациях запись истории активных сессий ведется. Для других БД - надо смотреть чтобы сбор данных мониторинга по времени происходил очень быстро. Если это запросы - то настраивать их на быстрое получение данных, если есть возможность другими способами снять трассировки - смотреть их.

      В случае плоской таблицы, средний размер строки без больших запросов порядка 100-300 байт, в тяжелом случае (большие тексты запросов) порядка 1 Кб и выше. Время между замерами - 1 секунда.

      Для 1000 сессий это примерно треть мегабайта данных для 300 байт средний размер строки. Их не проблема сохранить локально, и передать по сети и сохранить где-то еще.

      Для 1000 сессий 1Кб размер строки - уже возникают сложности в части передачи их по сети - 1 Мб локально сохранить не проблема.

      Поэтому в этом случае лучший вариант сохранять их на сервере (или где-то поблизости в спец. систему хранения для логов) и потом подтягивать на систему визуализации по мере необходимости. Аналогичная архитектура используется и в Oracle - история активных сессий сохраняется в БД локально.

      В случае Dimension-UI - в первом случае можно забирать данные с удаленной системы или сохранять на сервере и подтягивать изменения через интервал 3 секунды и более (BY_CLIENT_JDBC или BY_SERVER_JDBC). Для больших объемов, только второй вариант BY_SERVER_JDBC.

      Пределы по скорости записи для backend Dimension-UI (тут замеры производительности Dimension-DB) для локального индексирования дают значения порядка 10 Мб в секунду для сжатых данных (для несжатых умножаем на к=2-3).

      Скорость записи в МБ/сек.
      Скорость записи в МБ/сек.

      Т.е. схема с BY_CLIENT_JDBC будет работать даже на таких объемах, но задержки на сетевом уровне, при отправке данных - схема не очень надежная. В общем лучше использовать BY_SERVER_JDBC для больших объемов данных.