Базы данных (Data Base)
8.12K subscribers
604 photos
473 videos
19 files
603 links
Базы данных (Data Base). По всем вопросам @evgenycarter
Download Telegram
SQL JOINs наглядно: как работать с объединением таблиц

Хотите лучше понимать SQL JOIN? Вот наглядная шпаргалка с примерами и визуализацией!

🔹 INNER JOIN – пересечение двух таблиц, возвращает только совпадающие строки.

SELECT *
FROM A
INNER JOIN B ON A.key = B.key;


🔹 FULL JOIN – объединяет все данные из обеих таблиц, заполняя пропущенные значения NULL.

SELECT *
FROM A
FULL JOIN B ON A.key = B.key;


🔹 FULL JOIN с фильтрацией NULL – выбирает только строки, которые есть только в одной из таблиц.

SELECT *
FROM A
FULL JOIN B ON A.key = B.key
WHERE A.key IS NULL OR B.key IS NULL;


🔹 LEFT JOIN – возвращает все строки из A и совпадающие строки из B.

SELECT *
FROM A
LEFT JOIN B ON A.key = B.key;


🔹 LEFT JOIN (только уникальные в A) – возвращает только строки из A, которых нет в B.

SELECT *
FROM A
LEFT JOIN B ON A.key = B.key
WHERE B.key IS NULL;


🔹 RIGHT JOIN – аналогично LEFT JOIN, но с приоритетом B.

SELECT *
FROM A
RIGHT JOIN B ON A.key = B.key;


🔹 RIGHT JOIN (только уникальные в B) – выбирает строки, которые есть в B, но отсутствуют в A.

SELECT *
FROM A
RIGHT JOIN B ON A.key = B.key
WHERE B.key IS NULL;


Сохраняйте в закладки и пользуйтесь!

📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
Оптимизация запросов: как найти узкое место? 🔍

Привет, коллеги! Сегодня я покажу вам, как находить узкие места в SQL-запросах и оптимизировать их. Если ваш запрос работает медленно, скорее всего, проблема в одном из трех мест:

1️⃣ Неверные индексы
- Проверьте EXPLAIN ANALYZE, если используется Seq Scan вместо Index Scan, значит, индексы либо отсутствуют, либо неэффективны.
- Добавьте индексы на часто фильтруемые и соединяемые поля.

2️⃣ Проблемные JOIN'ы
- Проверьте, какие типы JOIN используются. NESTED LOOP JOIN может быть проблемой на больших таблицах.
- Используйте HASH JOIN или MERGE JOIN, если это возможно.

3️⃣ Громоздкие операции (GROUP BY, ORDER BY, DISTINCT)
- Сортировка и группировка требуют много ресурсов.
- Можно ли заменить DISTINCT на EXISTS?
- Используйте индексированные столбцы в ORDER BY.


📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🧠 Почему PostgreSQL иногда "зависает" на UPDATE и как это пофиксить

Сегодня я расскажу про одну интересную особенность PostgreSQL, с которой сталкивался лично: внезапные подвисания при UPDATE большого количества строк. Причём CPU почти не загружен, а запрос как будто "висит".

📌 Проблема часто кроется в отсутствии индекса на колонку фильтра в WHERE. Пример:


UPDATE orders SET status = 'archived' WHERE created_at < '2022-01-01';


Если на created_at нет индекса, то PostgreSQL делает sequential scan всей таблицы. А теперь внимание: если в таблице много "мертвых" строк, которых ещё не убрал autovacuum, то PostgreSQL должен:

1. Прочитать кучу ненужных версий строк (MVCC).
2. Проверять видимость каждой строки.
3. Иногда ещё и ждать завершения других транзакций, держащих старые снапшоты.

🛠 Что делать:
- Проверить наличие индекса на колонку фильтра:

CREATE INDEX idx_orders_created_at ON orders(created_at);

- Проверить состояние autovacuum:

SELECT relname, n_dead_tup, last_vacuum, last_autovacuum
FROM pg_stat_user_tables ORDER BY n_dead_tup DESC;

- Можно вручную запустить:

VACUUM ANALYZE orders;


🔥 Лайфхак: если UPDATE всё равно медленный, попробуй его разбить на батчи по 10 000 строк. Это снизит нагрузку и ускорит выполнение.

📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
💡7 обязательных стратегий для масштабирования вашей базы данных.

1 - Индексация:
Проверьте шаблоны запросов вашего приложения и создайте подходящие индексы.

2 - Материализованные представления:
Предварительно вычислите результаты сложных запросов и сохраните их для быстрого доступа.

3 - Денормализация:
Уменьшите количество сложных соединений (join), чтобы улучшить производительность запросов.

4 - Вертикальное масштабирование:
Увеличьте мощность вашего сервера базы данных, добавив больше ЦП, оперативной памяти или хранилища.

5 - Кэширование:
Сохраните часто запрашиваемые данные в более быстром слое хранения, чтобы снизить нагрузку на базу данных.

6 - Репликация:
Создайте реплики вашей основной базы данных на разных серверах для масштабирования чтений.

7 - Шардинг:
Разделите таблицы базы данных на более мелкие части и распределите их по серверам. Используется для масштабирования как записей, так и чтений.

📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
📊 Зачем DBA нужно уметь читать планы выполнения запросов (EXPLAIN)?

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

Когда приходит запрос от разработчика: "Почему тормозит?" - ты открываешь EXPLAIN (ANALYZE, BUFFERS) и видишь:


Seq Scan on users (cost=0.00..44231.00 rows=1000000 width=64)
Filter: (status = 'active')


И тут всё понятно: фильтрация идёт по колонке без индекса, Postgres делает полный проход по таблице. Один CREATE INDEX - и запрос летит 🚀

Но не всё так просто. Иногда план говорит:


Index Scan using idx_users_status on users
Index Cond: (status = 'active')


А запрос всё равно медленный. Почему?

➡️ Buffers: shared hit=5 read=100000 dirtied=0 - вот оно. Индекс-то используется, но данные не в кэше, приходится читать с диска. А диск медленный. Решение? Подумать о горячем кэше, пачке RAM или REINDEX, если индекс раздулся.

Каждый EXPLAIN - как рентген. Не читаешь - лечишь наугад.

📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
🚀 Подборка полезных 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 Свежие новости Москвы
🤡5
Сегодня расскажу вам про одну часто недооценённую, но крайне полезную 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🧩 Сегодня покажу вам простой, но крайне полезный приём, как находить “тяжёлые” запросы в 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍51🔥1
🎯 Сегодня покажу простой способ ускорить запросы в PostgreSQL, даже не трогая сам SQL-код.

Часто вижу, как разработчики и админы оптимизируют запросы, играя с индексами или переписывая JOIN'ы. Но забывают про один мощный инструмент — ANALYZE.

ANALYZE обновляет статистику по таблицам. Эта статистика — хлеб для планировщика запросов. Если она устарела, PostgreSQL может выбрать неэффективный план, даже если у вас всё индексировано как надо.

👨‍🔧 Простой пример:


ANALYZE my_big_table;


Запускаешь — и вдруг сложный JOIN срабатывает в разы быстрее. Потому что PostgreSQL теперь знает, какие там объемы данных, сколько уникальных значений в колонках и т.п.

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

Можно даже так:

VACUUM ANALYZE my_big_table;


Так ты и "мусор" уберёшь, и статистику обновишь за один проход.

📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥1
🧩 Как сделать 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🚀 Подборка полезных 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 Свежие новости Москвы
👎4🤬1
🚀 Сегодня покажу, как быстро диагностировать «тормоза» в 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥3
Кластер с приватной сетью 10 Гбит/с и дисковой производительностью до 1,5 млн IOPS — новая конфигурация в облачных базах данных на выделенных серверах Selectel.

Подходит для аналитики и других тяжёлых нагрузок, где важна физическая изоляция данных. А по стоимости — до 47% дешевле, чем стандартные решения.

Попробуйте сами, на тест дают до 30 000 бонусных рублей: https://slc.tl/0q42c

Реклама. АО "Селектел". erid:2W5zFGhZNUH
2
Как быстро найти “тяжёлые” запросы в 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍71
🧵 Сегодня я покажу вам простой, но мощный способ отладки сложных SQL-запросов

Когда у вас в проекте появляется монструозный запрос с десятками джойнов, подзапросов и оконных функций — ловить ошибки становится больно. Но есть подход, который реально спасает: инкрементальная отладка.

💡 Суть: разбиваем запрос на небольшие части и поочередно проверяем каждую

Вот как это делаю я:

1. Начинаю с ядра - самого внутреннего подзапроса или CTE. Проверяю, что он возвращает ожидаемые данные.
2. Добавляю следующий уровень логики - джойны, условия, группировки. Каждый раз выполняю и проверяю результат.
3. Для удобства использую WITH (CTE) - это даёт имена промежуточным результатам и делает запрос читабельным.
4. Сложные выражения и агрегаты выношу в отдельные CTE - это помогает быстрее изолировать проблему.
5. Если запрос очень тяжёлый - сохраняю промежуточные результаты в временные таблицы.

🔥 PostgreSQL позволяет использовать EXPLAIN (ANALYZE, BUFFERS) для профилирования на каждом этапе. Очень помогает найти, где тормозит.


📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
⚡️ Совет по работе с базами данных 💡

Уникальные индексы с исключением определенных строк

Создание уникальных индексов в некоторых случаях невозможно из-за дублирования значений - например, в строках, помеченных как «мягко удаленные» (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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
⚠️ Антипаттерн: использовать 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1🤡1
🚨 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
👍3🔥1
🆓 Ваши SQL-запросы работают, но через месяц их уже сложно прочитать и изменить?

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

На открытом уроке разберём
как использовать обобщенные табличные выражения (CTE), чтобы писать сложные запросы по шагам.
Покажем, как упростить структуру, сделать код читаемым и работать с иерархиями через рекурсивные CTE.

🗓 Урок проходит в преддверии старта курса «PostgreSQL для администраторов баз данных и разработчиков». Если вы хотите писать SQL, который легко читать и поддерживать — подключайтесь 21 мая в 20:00 МСК.

🔗 Регистрация открыта: https://vk.cc/cXMPz2

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
👍2
Антипаттерн: 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
👍3
🚨 Как понять, почему запрос тормозит?

Сегодня покажу простой, но действенный подход к диагностике медленных 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21