SQL-консоль
Прямой SQL по событиям своего проекта в ActionPulse — разрешённые запросы, доступные таблицы и поля, лимиты времени и результата, история запусков и рабочие примеры.
На этой странице
Консоль нужна там, где готовых отчётов не хватает: своя нарезка по свойству события, разовая сверка перед релизом, проверка гипотезы, для которой не стоит собирать отчёт. Это ровно то же хранилище, из которого считаются воронки и удержание, — но запрос пишете вы.
Экран — Данные и сбор → Запросы к данным. Запуск: кнопка «Выполнить» или Cmd/Ctrl+Enter.
Что можно выполнять
Разрешён ровно один запрос на чтение. Точнее:
- запрос начинается с
SELECTилиWITH; - это один statement — точка с запятой допускается только в самом конце;
JOIN, подзапросы,WITH-выражения, агрегатные функции и функции разбора JSON доступны обычным образом.
Отклоняется всё остальное — с кодом 422 и текстом, который называет
конкретную причину:
| Попытка | Что вернётся |
|---|---|
Два запроса через ; |
«multiple statements are not allowed» |
Запрос, начинающийся не с SELECT/WITH |
«only SELECT/WITH queries are allowed» |
| Изменение данных или схемы | отказ с указанием запрещённого слова |
| Обращение к внешнему источнику через табличную функцию | отказ с указанием запрещённой функции |
| Своя секция настроек запроса | отказ с указанием запрещённого слова |
| Незакрытый комментарий или кавычка | «unterminated comment», «unterminated quoted value» |
Проверка смотрит на слова вне строковых литералов и комментариев, а имена в кавычках разбирает как обычные слова — спрятать запрещённое слово в кавычках или обратных апострофах не получится.
Изоляция проекта
Область данных сужается до текущего проекта на стороне сервера, а не фильтром в вашем запросе. Практические следствия:
- условие
project_id = …писать не нужно: без него запрос уже видит только ваш проект; - добавить
project_idдругого проекта бессмысленно — строк не будет; - переключение проекта в кабинете меняет область данных консоли; черновик запроса при этом хранится отдельно для каждого проекта, так что переключение туда и обратно ничего не теряет.
Сообщения об ошибках базы наружу не проходят: вместо них приходит стабильный короткий отказ. Это сделано намеренно — текст исключения аналитической базы может содержать фрагменты запроса, имена объектов и детали устройства кластера.
Какие таблицы доступны
Панель схемы слева перечисляет всё, что можно читать; клик по имени вставляет его в позицию курсора. Доступны две таблицы.
events — по строке на событие:
| Колонка | Тип | Что это |
|---|---|---|
project_id |
UInt32 |
идентификатор проекта |
event_id |
UUID |
идентификатор события |
event_name |
LowCardinality(String) |
имя события |
actor_id |
String |
итоговый субъект: user_id, если он известен, иначе anon_id |
user_id |
String |
известный идентификатор пользователя |
anon_id |
String |
анонимный идентификатор |
session_id |
String |
сессия |
event_time |
DateTime64(3) |
когда событие произошло |
server_time |
DateTime64(3) |
когда событие пришло в ActionPulse |
props |
String (JSON) |
свойства события строкой JSON |
url |
String |
адрес страницы |
referrer |
String |
реферер |
utm_source, utm_medium, utm_campaign |
LowCardinality(String) |
UTM-метки |
device_type, os, browser |
LowCardinality(String) |
производные признаки клиента |
country |
LowCardinality(String) |
страна по IP-адресу |
event_catalog — сводка по именам событий: project_id, event_name,
last_seen (когда событие видели последний раз) и cnt (сколько его всего).
Удобно, когда нужно быстро понять, что вообще приходит в проект.
Сырого IP-адреса и строки user-agent в схеме нет — они не хранятся, из них
выводятся только country и признаки устройства. props — это строка JSON,
поэтому значения достаются функциями работы с JSON, а не точкой.
Лимиты
| Ограничение | Значение |
|---|---|
| Строк в результате | 100, 1000 или 10000 — выбирается в списке рядом с кнопкой запуска, по умолчанию 10000 |
| Время выполнения | 30 секунд |
| История запусков | последние 50 |
Под таблицей результата видно, сколько строк вернулось, сколько заняло выполнение и сколько строк было прочитано. Последнее число — лучший индикатор тяжести запроса: если прочитано на порядки больше, чем вернулось, скорее всего не отсекается период.
Результат не кэшируется: каждый запуск идёт в базу заново.
Примеры
Топ событий за неделю — то же, что делает готовый шаблон «Топ событий за неделю»:
SELECT event_name, count() AS c
FROM events
WHERE event_time > now() - INTERVAL 7 DAY
GROUP BY event_name
ORDER BY c DESC
LIMIT 20
Активные субъекты по дням за месяц:
SELECT toDate(event_time) AS day, uniqExact(actor_id) AS actors
FROM events
WHERE event_time >= now() - INTERVAL 30 DAY
GROUP BY day
ORDER BY day
Разрез по свойству события — здесь видно, как читается props:
SELECT JSONExtractString(props, 'plan') AS plan, count() AS c
FROM events
WHERE event_name = 'subscription_started'
AND event_time >= now() - INTERVAL 90 DAY
GROUP BY plan
ORDER BY c DESC
Полная лента одного человека (второй готовый шаблон, «События пользователя») —
подставьте свой идентификатор вместо YOUR_USER_ID:
SELECT *
FROM events
WHERE actor_id = 'YOUR_USER_ID'
ORDER BY event_time DESC
LIMIT 100
Кроме двух базовых шаблонов панель схемы показывает раздел «По вашим определениям» — запросы, собранные под ваше событие полезной активности. Они появляются после того, как это событие указано в реестре событий; до тех пор там стоит ссылка «Настроить определение».
Сохранённый отчёт типа SQL открывается сразу в консоли с подставленным текстом. Список отчётов лежит в Мониторинг → Отчёты.
Если запрос не уложился в 30 секунд
Приходит 408 с кодом query_timeout, в интерфейсе — статус «Таймаут». В
истории такой запуск сохраняется, так что текст запроса не теряется.
Что помогает, по убыванию эффекта:
- Сузить период.
event_time— первое, что отсекает данные. Запрос без границы по времени читает всю доступную историю. - Считать агрегат, а не выгружать строки.
SELECT *без агрегации на большом периоде почти всегда упирается либо в таймаут, либо в лимит строк. - Отфильтровать по
event_nameдо группировки. Имя события — низкокардинальная колонка, фильтр по нему стоит дёшево. - Не разбирать JSON по всей истории. Если нужен разрез по свойству, сначала
сузьте выборку по имени события и периоду, и только потом извлекайте значение
из
props. - Разбить на два запроса. Тяжёлый расчёт по кварталу часто быстрее собрать как три запроса по месяцу.
Если запрос нужен регулярно и упирается в лимиты — это сигнал, что задача переросла консоль: сохраните отчёт или посчитайте агрегат и выгрузите его, см. выгрузки.
История запусков
Вкладка «История» хранит последние 50 запусков проекта: время, автора, текст запроса, статус, длительность и число строк, плюс кнопку «Повторить».
Статусы: OK, Ошибка, Таймаут, Отклонён. В историю попадают все
запуски, включая отклонённые проверкой и не уложившиеся в лимит времени, — это
не только удобство, но и журнал: аналитик видит свои запуски, администратор и
владелец — все запуски по проекту. Записи журнала хранятся 90 дней.
Что проверить
- Результат ровно в 100, 1000 или 10000 строк — почти наверняка обрезан.
- Считаете людей — берите
uniqExact(actor_id), а неuser_id: у неопознанных посетителейuser_idпустой. - Считаете «когда произошло» — берите
event_time.server_timeпоказывает, когда событие дошло; у загруженной истории он равен моменту загрузки. - Нужен файл — кнопка «Экспорт CSV» на панели результата собирает его прямо в браузере из уже полученных строк. Это не серверная выгрузка: больше выбранного лимита строк она не отдаст.
- Не видите раздела на своём сервере — в self-hosted-установке консоль появляется только после того, как администратор настроил для неё отдельное подключение к аналитической базе.