Как выявить медленные SQL-запросы?

Ответ

Выявление медленных SQL-запросов критически важно для оптимизации производительности базы данных и всего приложения. Существует несколько эффективных подходов:

  1. Логирование медленных запросов на уровне БД: Большинство СУБД позволяют настроить логирование запросов, выполнение которых превышает заданный порог времени. Это отличный способ пассивного мониторинга.

    • PostgreSQL: В postgresql.conf установите:
      log_min_duration_statement = 1000  -- Логировать запросы, выполняющиеся дольше 1000 мс (1 секунды)
    • MySQL: В my.cnf включите slow_query_log и long_query_time.
  2. Анализ плана выполнения запроса (EXPLAIN ANALYZE): Этот инструмент позволяет увидеть, как база данных планирует и фактически выполняет запрос: какие индексы используются, порядок соединений таблиц, количество строк, время выполнения каждого шага.

    EXPLAIN ANALYZE SELECT id, name FROM products WHERE price > 100 ORDER BY created_at DESC;

    EXPLAIN (без ANALYZE) показывает только план, а EXPLAIN ANALYZE выполняет запрос и показывает фактические метрики.

  3. Инструменты профайлинга и статистики БД: СУБД предоставляют встроенные средства для сбора и анализа статистики по запросам.

    • PostgreSQL: Модуль pg_stat_statements отслеживает статистику по всем выполненным запросам, включая среднее время выполнения, количество вызовов и использование ресурсов.
    • MySQL: Performance Schema и sys schema предоставляют детальную информацию о производительности.
    • MS SQL Server: SQL Server Profiler или Extended Events.
  4. ORM-специфичные инструменты и отладка: Многие ORM (Object-Relational Mappers) имеют встроенные средства для просмотра выполненных SQL-запросов.

    • Django:

      from django.db import connection
      
      # Выполните ваши ORM-запросы здесь
      # MyModel.objects.filter(...).count()
      
      for query in connection.queries:
          print(f"Query: {query['sql']}, Time: {query['time']}")
    • SQLAlchemy: Можно настроить логирование запросов.
  5. Системы мониторинга производительности приложений (APM): Такие инструменты, как Datadog, New Relic, Sentry, Prometheus + Grafana, предоставляют комплексный мониторинг производительности, включая детализацию по SQL-запросам, их времени выполнения и частоте.

Ключевые метрики для анализа:

  • Время выполнения: Общее время, затраченное на запрос.
  • Количество строк: Сколько строк было прочитано и возвращено.
  • Использование индексов: Насколько эффективно используются индексы.
  • Блокировки: Наличие и длительность блокировок.
  • I/O операции: Количество операций чтения/записи на диск.

Оптимизация медленных запросов часто включает добавление индексов, переписывание запросов, денормализацию данных или изменение структуры схемы.

Ответ 18+ 🔞

А, ну вот, опять про эти ваши запросы, которые как черепахи в сиропе ползают! Слушай, давай по-простому, без этих заумных презентаций. База данных — это как тёща на кухне: если она начинает тормозить, всем пиздец, и ужин не готов, и нервы нахуй.

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

  • В PostgreSQL, например, лезешь в postgresql.conf и пишешь:
    log_min_duration_statement = 1000  # Всё, что дольше секунды — в лог, и пусть стыдно ей, суке, станет!
  • В MySQL тоже своя задвига есть, slow_query_log называется. Включаешь — и понеслась.

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

Второе — это разбор полётов, или «чё ты там, блядь, делал?». Нашёл медленный запрос? Отлично. Теперь заставляешь базу отчитаться по полной программе с помощью EXPLAIN ANALYZE. Это не просто EXPLAIN, который только план нарисует. Это ANALYZE, который реально выполнит запрос и тебе в лицо тыкнет: «Вот тут, смотри, ебаный Seq Scan на 5 миллионов строк был! Вот тут индекс, сука, не использовался! А тут соединение таблиц так криво прошло, что я сам офигел!».

EXPLAIN ANALYZE SELECT id, name FROM products WHERE price > 100 ORDER BY created_at DESC;

После этого вывода обычно хочется либо плакать, либо переписать всё с нуля.

Третье — шпионские штучки от самой базы. У них же там целые модули слежки за самими собой!

  • PostgreSQLpg_stat_statements. Этот модуль — как стукач-первач. Он всё запоминает: какой запрос сколько раз вызывали, сколько в среднем времени он жрал, сколько строк перелопатил. Установил, включил — и у тебя уже готов топ-10 самых прожорливых ублюдков.
  • MySQL со своей Performance Schema — та же фигня, только в профиль.
  • MS SQL тоже не лыком шит, у него свои профайлеры есть.

Четвёртое — копаемся в своём же дерьме, то есть в коде приложения. Ты же наверняка через какую-нибудь ORM работаешь? Так заставь её болтать!

  • В Django, например, можно так:

    from django.db import connection
    
    # ... тут твой код, который всё ломает ...
    
    for query in connection.queries:
        print(f"Запрос: {query['sql']}, Время: {query['time']}")  # Смотришь и офигеваешь: "И это я, блядь, написал?"
  • SQLAlchemy тоже умеет логировать, если её правильно попросить.

Пятое — тяжёлая артиллерия, APM-системы. Это когда ты уже не веришь ни себе, ни базе, и ставишь стороннего надзирателя. Datadog, New Relic... Эти ребята покажут тебе всё: не только какой запрос тормозит, но и в каком месте кода он родился, как часто его вызывают, и на каком фоне играет музыка, пока он выполняется. Стоит, конечно, овердохуища, но иногда без этого — как без рук.

На что смотреть, когда уже всё нашли?

  • Время выполнения: Очевидно же. Если дольше, чем твоё ожидание такси под дождём — плохо.
  • Количество строк: Запрос прочитал миллион строк, чтобы вернуть пять? Да ты, сука, оптимизатор!
  • Индексы: Они вообще использовались? Или база, как дура, всю таблицу сканировала? (Это тот самый страшный Seq Scan).
  • Блокировки: Один запрос повесил всё, потому что к ряду доступ как к священной корове? Бывает.
  • Ввод-вывод: Сколько раз к диску обратился? Если много — значит, памятью не разжился.

Итог обычно простой: либо индекс добавить, либо запрос переписать, чтобы не был идиотским, либо, в крайнем случае, схему данных перетряхнуть. Главное — начать с того, чтобы эти медленные уебаны просто найти. А там уже разберёшься, че с ними делать: оптимизировать или выпороть нахуй.