fa
Feedback
Базы данных (Data Base)

Базы данных (Data Base)

رفتن به کانال در Telegram

Базы данных (Data Base). По всем вопросам @evgenycarter

نمایش بیشتر
8 114
مشترکین
-224 ساعت
+37 روز
+130 روز
آرشیو پست ها
❌ Антипаттерн: Хранить даты и время в VARCHAR Встречали такое? CREATE TABLE orders ( id SERIAL PRIMARY KEY, order_date VARCHA
❌ Антипаттерн: Хранить даты и время в VARCHAR Встречали такое?

CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  order_date VARCHAR(20)
);
На первый взгляд — всё ок: дата есть, строка хранит. Но на практике — сплошные проблемы: 🔴 Нет гарантии формата '2024-12-01', '12/01/2024', '01.12.24', 'вчера' — всё ляжет, но работать с этим потом боль. 🔴 Сложность фильтрации и сортировки Сравнение строк ≠ сравнение дат. Запросы типа WHERE order_date > '2024-01-01' могут вести себя непредсказуемо. 🔴 Нельзя использовать функции времени Ни DATE_TRUNC, ни AGE(), ни агрегаты по времени не работают нормально с VARCHAR. ✅ Как правильно Используйте типы DATE, TIMESTAMP, TIMESTAMPTZ — они: * валидируют данные на вставке; * дают мощный инструментарий для анализа; * упрощают работу с часовыми поясами и интервалами.

CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  order_date TIMESTAMPTZ DEFAULT now()
);
💡 Если данные приходят в виде строк — парси их при загрузке, а не храни как есть. Сохрани, чтобы не наступить на эти же грабли ☝️ А как у вас хранят даты? 📲 Мы в MAX #db 👉 @database_info

🔎 Мини-гайд: Индексы в PostgreSQL — быстро и по делу Индексы — главный инструмент для ускорения запросов. Но неправильное ис
🔎 Мини-гайд: Индексы в PostgreSQL — быстро и по делу Индексы — главный инструмент для ускорения запросов. Но неправильное использование может только навредить. Основные типы индексов в PostgreSQL: - B-tree — по умолчанию. Идеален для поиска по равенству и диапазону (=, <, >, BETWEEN). - Hash — только для поиска по точному равенству (=). Становится актуальным реже. - GIN — для массивов, JSONB, полнотекстового поиска. - GiST — геоданные, поиск по диапазонам, сложные типы. - BRIN — для очень больших таблиц с упорядоченными данными (например, логи). Практические советы: - Не злоупотребляй индексами: каждый индекс замедляет INSERT/UPDATE/DELETE. - Следи за актуальностью: периодически проверяй и удаляй неиспользуемые (pg_stat_user_indexes поможет). - Составные индексы ((col1, col2)) эффективны, только если условия WHERE учитывают порядок колонок. - Используй EXPLAIN ANALYZE, чтобы понять, работает ли индекс в реальности. Типичная ошибка: Создать индекс на всё подряд без анализа запросов. Итог — тормоза на записи и огромный размер базы. ✅ Индексы — это как специи: мало — пресно, много — несъедобно. Вывод: Хотите быструю базу — планируйте индексацию так же внимательно, как сами запросы. Сохрани, чтобы не забыть! 📲 Мы в MAX #db 👉 @database_info

Сегодня я хочу рассказать вам про одну часто недооцененную фишку в PostgreSQL - partial indexes (частичные индексы). Обычно м
Сегодня я хочу рассказать вам про одну часто недооцененную фишку в PostgreSQL - partial indexes (частичные индексы). Обычно мы создаём индексы на всю таблицу, но что если нам нужно ускорить только небольшую часть данных? Например, часто выбираются только активные пользователи (status = 'active'). Вместо полного индекса можно создать индекс только для нужного поднабора данных:

CREATE INDEX idx_active_users
ON users (last_login)
WHERE status = 'active';
Что это даёт: - Индекс меньше по размеру → быстрее поиск и обновление. - Используется только тогда, когда запрос соответствует условию status = 'active'. - Меньше нагрузка на диск при обновлениях таблицы. 🛠 Где это реально помогает: - Таблицы с миллионами записей, где активно работают только с частью строк. - Сценарии "горячих" и "холодных" данных. Рекомендую попробовать partial indexes там, где обычные индексы слишком тяжелы или тормозят обновления! 📲 Мы в MAX #db 👉 @database_info

Как перейти от простого обнаружения объектов к работающим сценариям мониторинга? На основе координат из YOLO и данных трекера строим аналитику: пересечение виртуальных линий, контроль запретных зон, расчет времени нахождения в области. Математика перемещений превращается в конкретные бизнес-события. Результаты урока: Освоите работу с зонами интереса, научитесь подсчитывать события на видео и строить стабильные конвейеры «детектор + трекер + логика». Спикер и руководитель курса по CV: Антон Витвицкий, руководитель команды компьютерного зрения в Boost Inc., опыт 14+ лет Регистрируйтесь сейчас — напомним накануне: регистрация Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

🚀 Сегодня я покажу вам один из моих любимых хаков для PostgreSQL – генерация серий дат без циклов и хранимок. Это идеальный
🚀 Сегодня я покажу вам один из моих любимых хаков для PostgreSQL – генерация серий дат без циклов и хранимок. Это идеальный способ быстро собрать таймлайн для аналитики или отчётов. Сценарий: вам нужно построить список всех дат за последний месяц — например, чтобы потом сделать LEFT JOIN к таблице с событиями и увидеть, где были пропуски. Вот как это делается с помощью generate_series:

SELECT generate_series(
    date_trunc('day', current_date) - interval '30 days',
    date_trunc('day', current_date),
    interval '1 day'
) AS day;
💡 Результат — 31 строка с датами от 30 дней назад до сегодняшнего дня. Теперь добавим, например, LEFT JOIN к таблице events, чтобы увидеть активность по дням:

SELECT
    d.day,
    COUNT(e.id) AS events_count
FROM
    generate_series(
        date_trunc('day', current_date) - interval '30 days',
        date_trunc('day', current_date),
        interval '1 day'
    ) AS d(day)
LEFT JOIN events e ON date_trunc('day', e.created_at) = d.day
GROUP BY d.day
ORDER BY d.day;
📊 Отлично подходит для дашбордов, когда нужно увидеть, где были дни без событий. Пользуетесь ли вы generate_series? А может быть, используете что-то подобное в других СУБД? Делитесь в комментариях👇 📲 Мы в MAX #db 👉 @database_info

🚨 Как понять, почему запрос тормозит? Сегодня покажу простой, но действенный подход к диагностике медленных SQL-запросов. Ко
🚨 Как понять, почему запрос тормозит? Сегодня покажу простой, но действенный подход к диагностике медленных SQL-запросов. Когда к тебе приходит прод с жалобой "что-то всё виснет", важно не паниковать, а системно подойти к анализу. Вот что я делаю первым делом: 1. Включаю EXPLAIN (ANALYZE) Это ваш лучший друг. Не EXPLAIN, а именно ANALYZE, чтобы получить реальные значения времени, а не план на бумаге. 2. Смотрю на узлы с наибольшим временем Часто виновник — Seq Scan по большой таблице или Nested Loop с миллионами итераций. 3. Ищу несработавшие индексы Был ли Index Scan или Index Only Scan? Если нет — стоит проверить, почему не сработал индекс. Может, фильтр не селективный? 4. Проверяю фильтрацию и сортировку ORDER BY может убить всё. Особенно если не по индексу. 5. Думаю про статистику ANALYZE делали недавно? PostgreSQL может строить плохой план, если у него устаревшие данные. 🛠 Если ты часто отлаживаешь SQL — советую поставить pgMustard или использовать EXPLAIN DEPOT. Они визуализируют планы и сразу показывают узкие места. 📲 Мы в MAX #db 👉 @database_info

Антипаттерн: NULL в WHERE — и ты в ловушке Когда в таблице есть NULL, а в WHERE ты пишешь что-то вроде: SELECT * FROM users W
Антипаттерн: NULL в WHERE — и ты в ловушке Когда в таблице есть NULL, а в WHERE ты пишешь что-то вроде:

SELECT * FROM users WHERE age != 30;
Ты ожидаешь, что выберутся все, кто не 30. Но если age IS NULL — такие строки пропадут из выборки! Почему? Потому что NULL != 30 не TRUE, это UNKNOWN. А SQL возвращает строки только там, где WHERETRUE. Как избежать? 1. Будь явно осторожен с NULL:

   SELECT * FROM users 
   WHERE age != 30 OR age IS NULL;
   
2. Логика на уровне схемы: – Если поле нужно всегда — делай NOT NULL. – Если допускаешь NULL, продумывай поведение выборок. 3. Не верь глазам своим: Даже count(*) и count(column) ведут себя по-разному из-за NULL. Вывод: NULL — это не ноль, не пустая строка и не "ничего". Это "мы не знаем". И SQL ведёт себя с ним очень осторожно. Сохрани, чтобы не словить грабли. 📲Мы в MAX #db 👉 @database_info

🆓 Ваши SQL-запросы работают, но через месяц их уже сложно прочитать и изменить? С ростом логики запросы превращаются в набор
🆓 Ваши SQL-запросы работают, но через месяц их уже сложно прочитать и изменить? С ростом логики запросы превращаются в набор вложенных подзапросов. Разобраться в них сложно, поддержка занимает время, а любые изменения несут риск сломать результат. На открытом уроке разберём как использовать обобщенные табличные выражения (CTE), чтобы писать сложные запросы по шагам. Покажем, как упростить структуру, сделать код читаемым и работать с иерархиями через рекурсивные CTE. 🗓 Урок проходит в преддверии старта курса «PostgreSQL для администраторов баз данных и разработчиков». Если вы хотите писать SQL, который легко читать и поддерживать — подключайтесь 21 мая в 20:00 МСК. 🔗 Регистрация открыта: https://vk.cc/cXMPz2 Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

🚨 SELECT * - скрытый враг в проде На dev-сервере всё шустро. В проде — беда: запросы висят, база потеет. И вроде бы всё ок..
🚨 SELECT * - скрытый враг в проде На dev-сервере всё шустро. В проде — беда: запросы висят, база потеет. И вроде бы всё ок... пока не заглянешь в SQL:

SELECT * FROM users WHERE status = 'active';
На первый взгляд — удобно. Но: 🔻 Проблемы “SELECT *”: – Тянет все колонки, даже ненужные. А их может быть 30+. – Увеличивает нагрузку на сеть и память приложения. – Ломает кэш — ведь даже малейшие изменения в колонках меняют структуру результата. – Убивает индекс-only scan: Postgres не может использовать покрывающий индекс, если явно не указаны поля. ✅ Как надо: 🎯 Выбирай только нужные поля:

SELECT id, name, email FROM users WHERE status = 'active';
💡 Хочешь “быстро протестить” в dev-е? Ок. Но не пускай такое в прод. Автоматизируй линтинг SQL, если надо. Вывод: SELECT * — это не “удобно”, это дорого. И ты за него уже платишь. Сохрани, чтобы не словить боль в проде. А у тебя где последний раз встречалось SELECT *? 📲Мы в MAX #db 👉 @database_info

⚠️ Антипаттерн: использовать NULL без оглядки На первый взгляд NULL — это просто “нет значения”. Но в реальности — это тихий
⚠️ Антипаттерн: использовать NULL без оглядки На первый взгляд NULL — это просто “нет значения”. Но в реальности — это тихий саботаж: 🔸 NULL != NULL. Да-да, сравнение NULL = NULL даст false или unknown. Это ломает привычную логику и может убить фильтры. 🔸 Агрегации ведут себя странно. COUNT(column) не считает NULL'ы. AVG, SUM — тоже их игнорируют. Итог: неверная статистика. 🔸 Индексы и WHERE column IS NULL. Не все СУБД эффективно используют индексы при таких запросах. Можно словить тормоза. 🔸 NOT IN + NULL = 💥. Запрос WHERE id NOT IN (subquery) может вернуть пустой результат, если в подзапросе есть хотя бы один NULL. 💡 Как избежать проблем: 1. Всегда осознанно работай с NULL — используй IS NULL и IS NOT NULL, не = и !=. 2. По возможности избегай NULL в колонках, где это не нужно. Лучше использовать значения по умолчанию. 3. Добавляй проверки в коде: COALESCE, IFNULL, NVL и аналоги. 4. Понимай, как твоя СУБД работает с NULL в индексах и фильтрах. 🎯 Вывод: NULL — не пустота, а “неизвестность”. Обращайся с ним осторожно, иначе баги будут неявными и неприятными. Сохрани, чтобы не отловить баг на проде 🐛 📲 Мы в MAX #db 👉 @database_info

⚡️ Совет по работе с базами данных 💡 Уникальные индексы с исключением определенных строк Создание уникальных индексов в неко
⚡️ Совет по работе с базами данных 💡 Уникальные индексы с исключением определенных строк Создание уникальных индексов в некоторых случаях невозможно из-за дублирования значений - например, в строках, помеченных как «мягко удаленные» (soft-deleted). Исключив такие строки из индекса, можно корректно настроить ограничение уникальности. В MySQL частичные уникальные индексы (unique partial indexes) требуют эмуляции. В современных базах данных часто используется паттерн Soft Delete, когда данные не удаляются физически, а помечаются флагом is_deleted = true. Если вы хотите, чтобы поле email было уникальным только для активных пользователей, обычный уникальный индекс выдаст ошибку при попытке регистрации нового пользователя с почтой, которая уже есть в «корзине». Использование частичного индекса решает эту проблему, позволяя игнорировать помеченные на удаление записи. Нюанс для MySQL: В отличие от PostgreSQL или SQL Server, MySQL не поддерживает синтаксис WHERE внутри команды CREATE INDEX. Чтобы добиться такого же поведения, разработчики обычно используют: • Виртуальные колонки (Generated Columns): создается колонка, которая принимает значение только если запись активна, и на нее вешается уникальный индекс. • Составные индексы: включение флага удаления или временной метки в сам индекс. 📲 Мы в MAX #db 👉 @database_info

🧵 Сегодня я покажу вам простой, но мощный способ отладки сложных SQL-запросов Когда у вас в проекте появляется монструозный
🧵 Сегодня я покажу вам простой, но мощный способ отладки сложных SQL-запросов Когда у вас в проекте появляется монструозный запрос с десятками джойнов, подзапросов и оконных функций — ловить ошибки становится больно. Но есть подход, который реально спасает: инкрементальная отладка. 💡 Суть: разбиваем запрос на небольшие части и поочередно проверяем каждую Вот как это делаю я: 1. Начинаю с ядра - самого внутреннего подзапроса или CTE. Проверяю, что он возвращает ожидаемые данные. 2. Добавляю следующий уровень логики - джойны, условия, группировки. Каждый раз выполняю и проверяю результат. 3. Для удобства использую WITH (CTE) - это даёт имена промежуточным результатам и делает запрос читабельным. 4. Сложные выражения и агрегаты выношу в отдельные CTE - это помогает быстрее изолировать проблему. 5. Если запрос очень тяжёлый - сохраняю промежуточные результаты в временные таблицы. 🔥 PostgreSQL позволяет использовать EXPLAIN (ANALYZE, BUFFERS) для профилирования на каждом этапе. Очень помогает найти, где тормозит. 📲 Мы в MAX #db 👉 @database_info

Как быстро найти “тяжёлые” запросы в PostgreSQL Сегодня покажу простой способ найти самые ресурсоёмкие запросы, которые прямо сейчас выполняются в PostgreSQL. Это помогает, когда база начинает “тормозить”, а понять почему - сложно. Используем pg_stat_activity и pg_stat_statements. Но сначала убедись, что pg_stat_statements включён: -- Проверка: SELECT * FROM pg_extension WHERE extname = 'pg_stat_statements'; -- Включение (если не установлен): CREATE EXTENSION pg_stat_statements; Теперь сам запрос на поиск “тяжёлых” запросов: SELECT query, calls, total_exec_time, mean_exec_time, rows FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5; А если интересует то, что прямо сейчас выполняется — тогда так: SELECT pid, now() - query_start AS duration, state, query FROM pg_stat_activity WHERE state != 'idle' ORDER BY duration DESC; Я часто сохраняю эти запросы в отдельный .sql-файл, чтобы запускать сразу при проблемах с производительностью. Полезно добавить в .psqlrc алиас или даже обернуть в скрипт. Как вы ищете “тяжёлые” запросы в проде? Поделитесь в комментариях. 📲 Мы в MAX #db 👉 @database_info

Кластер с приватной сетью 10 Гбит/с и дисковой производительностью до 1,5 млн IOPS — новая конфигурация в облачных базах данн
Кластер с приватной сетью 10 Гбит/с и дисковой производительностью до 1,5 млн IOPS — новая конфигурация в облачных базах данных на выделенных серверах Selectel. Подходит для аналитики и других тяжёлых нагрузок, где важна физическая изоляция данных. А по стоимости — до 47% дешевле, чем стандартные решения. Попробуйте сами, на тест дают до 30 000 бонусных рублей: https://slc.tl/0q42c Реклама. АО "Селектел". erid:2W5zFGhZNUH

🚀 Сегодня покажу, как быстро диагностировать «тормоза» в PostgreSQL - без всяких внешних тулов и дополнительных логов. Только pg_stat_activity и немного здравого смысла. Пользователи жалуются - "всё тормозит". Как понять, что именно? Открываем сессию в psql от суперпользователя и запускаем:

SELECT pid, state, wait_event_type, wait_event, query, now() - query_start AS duration
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY duration DESC;
📌 Что это нам даёт: - Видим все активные (и зависшие) запросы. - Сколько времени они уже выполняются (duration). - На чём конкретно «висят»: CPU, IO, Lock, Client и т.д. (wait_event_type + `wait_event). Пример:
wait_event_type: Lock
wait_event: relation
→ Сразу ясно: кто-то держит блокировку на таблицу, и все остальные ждут. 🔥Чтобы найти виновника, можно запустить:

SELECT blocked_locks.pid AS blocked_pid,
       blocking_locks.pid AS blocking_pid,
       blocked_activity.query AS blocked_query,
       blocking_activity.query AS blocking_query
FROM pg_locks blocked_locks
JOIN pg_locks blocking_locks ON blocked_locks.locktype = blocking_locks.locktype
  AND blocked_locks.database IS NOT DISTINCT FROM blocking_locks.database
  AND blocked_locks.relation IS NOT DISTINCT FROM blocking_locks.relation
  AND blocked_locks.page IS NOT DISTINCT FROM blocking_locks.page
  AND blocked_locks.tuple IS NOT DISTINCT FROM blocking_locks.tuple
  AND blocked_locks.transactionid IS NOT DISTINCT FROM blocking_locks.transactionid
  AND blocked_locks.classid IS NOT DISTINCT FROM blocking_locks.classid
  AND blocked_locks.objid IS NOT DISTINCT FROM blocking_locks.objid
  AND blocked_locks.objsubid IS NOT DISTINCT FROM blocking_locks.objsubid
  AND blocked_locks.pid != blocking_locks.pid
JOIN pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;
Этот запрос покажет, кто кого блокирует, и с каким запросом. 🙌 Это простая, но мощная техника диагностики. Помогала мне не раз в проде - особенно, когда времени мало, а багов много. Ты пользуешься pg_stat_activity в проде? Или сразу лезешь в лог? Расскажи в комментах! 📲 Мы в MAX #db 👉 @database_info

🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии 📌 https://max.ru/progjob Вакансии в IT Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы

🧩 Как сделать backup PostgreSQL с минимальной нагрузкой на прод? Сегодня покажу один из самых эффективных способов бэкапа PostgreSQL — с помощью pg_basebackup + реплики. Сценарий: у нас есть продовый PostgreSQL и настроенная горячая реплика (streaming replication). Зачем использовать реплику для бэкапа? Причины: - 💡 На проде бэкап может замедлить отклик приложения. - 🔁 Реплика — отличный способ разгрузить основной сервер. - ⏱ Бэкап с pg_basebackup возможен только на стопнутой БД или через репликацию. Как сделать:

pg_basebackup -h replica.host -U repl_user -D /backup/pg -F tar -z -P
Пояснения: - -h — адрес реплики - -U — пользователь с правами репликации - -D — куда класть бэкап - -F tar -z — формат архива и сжатие - -P — прогресс в консоли Важно: Пользователь repl_user должен быть прописан в pg_hba.conf и иметь роль REPLICATION. А если добавить в cron, то получишь стабильный ночной бэкап без боли. 📲 Мы в MAX #db 👉 @database_info

🎯 Сегодня покажу простой способ ускорить запросы в PostgreSQL, даже не трогая сам SQL-код. Часто вижу, как разработчики и админы оптимизируют запросы, играя с индексами или переписывая JOIN'ы. Но забывают про один мощный инструмент — ANALYZE. ANALYZE обновляет статистику по таблицам. Эта статистика — хлеб для планировщика запросов. Если она устарела, PostgreSQL может выбрать неэффективный план, даже если у вас всё индексировано как надо. 👨‍🔧 Простой пример:

ANALYZE my_big_table;
Запускаешь — и вдруг сложный JOIN срабатывает в разы быстрее. Потому что PostgreSQL теперь знает, какие там объемы данных, сколько уникальных значений в колонках и т.п. 🧠 Совет: если ты регулярно заливаешь данные в таблицы (например, через ETL или бэкапы) — добавь ANALYZE в конец процедуры. Это дёшево, но может дать мощный прирост производительности. Можно даже так:

VACUUM ANALYZE my_big_table;
Так ты и "мусор" уберёшь, и статистику обновишь за один проход. 📲 Мы в MAX #db 👉 @database_info

🧩 Сегодня покажу вам простой, но крайне полезный приём, как находить “тяжёлые” запросы в PostgreSQL, которые тормозят базу. 📌 Если у вас база под нагрузкой, и “что-то всё стало медленно”, первым делом проверьте:

SELECT pid, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active'
ORDER BY duration DESC
LIMIT 5;
Этот запрос показывает топ-5 самых долгих активных запросов. Обратите внимание на query_start - именно он поможет понять, кто завис и тормозит остальных. А если хотите посмотреть историю медленных запросов за последние часы/дни - подключайте pg_stat_statements:

SELECT 
  calls, 
  total_time, 
  mean_time, 
  query 
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10;
🔍 Тут видно, какие запросы в сумме "съели" больше всего времени. И это гораздо честнее, чем смотреть только на mean_time или calls по отдельности. 💡Совет: подключите pg_stat_statements на проде и делайте такой анализ хотя бы раз в неделю. Это поможет находить проблемные места в приложении до того, как начнётся пожар. 📲 Мы в MAX #db 👉 @database_info

Сегодня расскажу вам про одну часто недооценённую, но крайне полезную SQL-фишку — CROSS APPLY в SQL Server (и его аналог в других СУБД — LATERAL). Когда обычный JOIN бессилен Допустим, у нас есть таблица Orders, и мы хотим для каждой строки выбрать топ-1 продукт по сумме, но выборка зависит от строки — тут уже обычный JOIN не справится. Вот пример, где приходит на помощь CROSS APPLY:

SELECT 
    o.OrderID,
    p.ProductName,
    p.Amount
FROM Orders o
CROSS APPLY (
    SELECT TOP 1 *
    FROM Products p
    WHERE p.OrderID = o.OrderID
    ORDER BY p.Amount DESC
) p;
Что делает CROSS APPLY? Он буквально говорит: «Для каждой строки из Orders выполни подзапрос с её параметрами». Это похоже на foreach, где внутренняя выборка может меняться в зависимости от строки внешней таблицы. Аналог в PostgreSQL:

SELECT 
    o.order_id,
    p.product_name,
    p.amount
FROM orders o,
LATERAL (
    SELECT *
    FROM products p
    WHERE p.order_id = o.order_id
    ORDER BY p.amount DESC
    LIMIT 1
) p;
🔥 Используйте CROSS APPLY, когда: - Нужна подстрочная логика внутри запроса - Не получается реализовать через обычный JOIN - Вы работаете с функциями, которые возвращают таблицу (TVF) 📲 Мы в MAX #db 👉 @database_info