Быстродействие сайтаВеб-разработка

Почему страница думала три секунды: запрос, которого не видно в коде страницы

16 августа 2026 года наш сайт отвечал за 3,05 с, а соседи на том же сервере — за 0,2–0,3 с. Виноват запрос мега-меню, который на каждой странице тянул 4,3 МБ переводов. Разбираем его и ещё три похожих случая, а также как найти такое на своём сайте.

16 августа 2026 года наш собственный сайт отвечал за 3,05 секунды. Соседние проекты на том же сервере отвечали за 0,2–0,3 секунды. То есть хостинг был ни при чём: одна машина, одна сеть, разница в десять раз.

Причину мы нашли не в коде страницы, а в блоке, который стоит на каждой странице и на который никто не смотрит. Ниже разбор того случая и ещё трёх похожих, которые мы исправили до 5 сентября, с цифрами до и после. В конце покажем, как за 10–15 минут проверить то же самое на своём сайте.

Меню в шапке, которое весило 4,3 МБ

Мы замеряли не страницу целиком, а каждый источник данных отдельно. Один запрос занимал 1 791 мс из 2,4 секунды всего рендера. Это был запрос для мега-меню в шапке, то есть он выполнялся на любой странице сайта: на главной, в статье, на странице услуги.

Меню нужны три коротких поля на пункт: название, заголовок и краткое описание. Запрос брал 185 строк вместе со столбцом переводов. А в том столбце лежали не только названия, но и полный текст каждой страницы на трёх языках: 23 КБ на строку, 4,3 МБ на все. Чтобы прочитать несколько сотен байтов, база каждый раз отдавала мегабайты.

Лучшая деталь: над этим запросом стоял комментарий «лёгкий срез — без тяжёлого content JSON». Буквально комментарий не врал. Поле с текстом страницы действительно не выбиралось отдельно, но оно лежало внутри поля перевода, которое выбиралось целиком.

Почему этого никто не заметил

Потому что в коде страницы этого запроса нет. Открываешь шаблон статьи, и там только запросы самой статьи. Меню живёт в шапке, шапка в общем макете, и когда ищут, почему медленная статья, смотрят в статью.

К тому же запрос не был ошибочным. Он возвращал правильные данные, меню показывало правильные пункты. Медленный запрос, который работает правильно, сам о себе не сообщает.

Исправили в два шага. Сначала нужные поля стали забираться отдельным запросом по конкретным путям внутри JSON, а не целым столбцом. Сам этот запрос ускорился с 1 891 до 107 мс. Потом готовое дерево меню положили в кеш данных на час, со сбросом, когда в админке публикуют страницу. Второе важнее: с кешем этот запрос на большинстве показов не выполняется вообще.

Тот же узор ещё трижды

После меню мы начали искать именно такие места: невидимые со страницы и одинаковые для каждого показа. Нашлось ещё три.

Настройки сайта, 23 августа. Каждый рендер любой публичной страницы читал таблицу настроек 7–8 раз: теги аналитики (дважды, в двух разных местах), строки для структурированных данных, флажок индексации, список включённых языков. Эти значения меняют из админки редко, а читались они на каждый запрос. В тот день мы замерили 0,46 с на простой странице и 0,72 с на сложной, при том что статический файл с того же сервера приходил за 0,30 с. Чтение обернули в кеш со сроком жизни 60 секунд и сбросом при сохранении. Почему ещё и минута, а не только сброс: писать в ту таблицу умеют как минимум двенадцать мест в коде, и пропустить одно очень легко. Кеш без сброса хуже отсутствия кеша, потому что правка из админки просто не появляется.

Страницы услуг, 5 сентября. Страницы сети услуг отвечали за 0,45–0,5 с, хабы разделов за 0,17 с, статьи блога за 0,36–0,43 с. Виноват блок «смежные услуги» внизу страницы: он выбирал до 60 соседей вместе с полными переводами. Выходило 1,1–1,3 МБ JSON против 65 КБ всех остальных данных страницы, хотя ссылкам нужны только название и заголовок на одном языке. Та же ошибка, что и в меню, только в другом месте. Заодно выяснилось, что строка самой страницы читалась дважды: для метаданных и для тела.

Автоматические ссылки в статьях, 5 сентября. Здесь виновата уже не база, а процессор. Профиль показал, что самая большая единичная статья расходов на странице статьи — подстановка внутренних ссылок. На каждый из примерно 2 000 ключей собиралось регулярное выражение и прогонялось по всему тексту. Это 35 мс процессора на показ, а на общем сервере с load average 5–9 эти миллисекунды растягивались в более чем 0,1 с ответа. Заменили на поиск подстроки с проверкой границ слова. Старую и новую версию сравнили на 679 текстах (все опубликованные статьи и вступления страниц на трёх языках): результат побайтово одинаковый. Самая тяжёлая статья обрабатывается за 5,6 мс вместо 18,9, весь набор за 464 мс вместо 1 451.

Честная оговорка: цифры «до» в этих случаях сняты в разные дни и разными способами. Это не одна кривая, а четыре отдельные истории, и складывать их в одно «ускорили в N раз» было бы неправдой.

Сколько сейчас и при чём здесь сеть

16 сентября 2026 года около 20:40 по Киеву мы повторили замер. С самого сервера до публичного адреса сайта, по 5 запросов на адрес, медиана времени до первого байта:

Тип страницы Медиана
страницы услуг, 6 адресов на трёх языках 0,211–0,266 с
статьи, 3 адреса 0,222–0,307 с
хаб раздела 0,216 с
«О нас» 0,178 с
главная 0,346 с

Load average сервера в момент замера был 6,1, то есть это цифры под обычной для него нагрузкой, а не на пустой машине.

Теперь то, что видит человек в Украине. С нашего ПК, по 6 запросов:

Адрес До первого байта
статический файл логотипа 0,185–0,215 с
«О нас» 0,254–0,362 с
статья 0,319–0,394 с
главная 0,328–0,433 с

Статический файл сайт не рендерит вообще, он просто лежит на диске. И всё равно 0,19–0,22 секунды, из них около 0,1 с только на установку соединения. Это пол: ниже него оптимизация кода не опустит, потому что это расстояние и сеть, а не программа.

Как проверить свой сайт за 10–15 минут

1. Снимите пол. Возьмите любой статический файл своего сайта (логотип, CSS) и страницы, которые вас беспокоят:

for u in /logo.svg / /katalog/; do
  printf "%s ::" "$u"
  for i in 1 2 3 4 5 6; do
    curl -s -o /dev/null -w " %{time_starttransfer}" "https://ваш-сайт.com.ua$u"
  done; echo
done

От времени страницы отнимите время статического файла. Остаток — это работа вашего сервера и вашего кода. Если остаток несколько десятков миллисекунд, в коде искать нечего, вопрос в сети или в расположении сервера. Если секунда, читайте дальше.

2. Сравните разные типы страниц. Главная, категория, карточка товара, статья, «Контакты». Если медленные все одинаково, даже самые простые, причина почти наверняка в том, что есть на каждой странице: шапка, меню, футер, настройки. Если медленная только категория, смотрите её собственные запросы.

3. Найдите тяжёлый запрос. Включите журнал медленных запросов и откройте страницу несколько раз. Для MySQL:

SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 0.1;

Для PostgreSQL с расширением pg_stat_statements:

SELECT round(mean_exec_time) AS ms, calls, left(query, 120)
FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;

Запрос с большим calls и заметным временем — главный подозреваемый: он выполняется на каждый показ.

4. Посмотрите, сколько весят столбцы, которые он берёт. В нашем случае время уходило не на поиск, а на перебрасывание данных. В PostgreSQL:

SELECT avg(pg_column_size(название_столбца)) FROM название_таблицы;

Если запрос для меню берёт столбец на десятки килобайтов на строку, а показывает из него одно слово, вы нашли то же самое, что и мы.

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

Что это не исправило

Самое важное ограничение видно в данных реальных посетителей. За 28 дней до 7 сентября 2026 года 75-й перцентиль времени до первого байта на мобильных был 893 мс (109 замеров), на десктопах 654 мс (124 замера). Учитываются только посетители, которые согласились на аналитику, а окно частично захватывает период до исправлений 5 сентября. Но разрыв между 0,2 с на сервере и почти 0,9 с на телефоне — это преимущественно мобильная сеть, и кодом сайта его не убрать. Помочь могла бы только отдача готовых страниц из кеша, без рендера. Украинские страницы у нас до сих пор рендерятся на каждый запрос: в их адресах нет языкового префикса, путь переписывается, а переписанный запрос идёт мимо кеша страниц.

У кеширования есть и своя цена. Меню обновляется сразу после публикации в админке, а вот настройки сайта могут отставать до минуты. Мы на это сознательно согласились.

Вывод, который переносим на любой сайт: прежде чем винить хостинг или CMS, снимите пол статическим файлом, а потом ищите один тяжёлый запрос в блоке, который стоит на каждой странице. Если заниматься этим самим нет времени, мы делаем аудит скорости сайта и ускорение с такими же замерами до и после. Какие числа скорости вообще измерять, разобрано отдельно, а про вес страницы и сжатие есть история про 170 КБ вместо 76.

Теги

PerformanceАналитика

Вам понравилась статья?

Ваше мнение помогает нам создавать лучший контент

Поделитесь с друзьями

Нашли что-нибудь полезное?

Помогите другим узнать это — поделитесь статьей в социальных сетях

Спасибо, что помогаете нам расти

Основатель LIONEX

Владислав Чистяков

Пишет о том, что делает руками: интернет-магазины на OpenCart, приложения на Next.js, интеграции и скорость сайтов. В статьях — замеры и проверки, которые читатель может повторить на своём проекте, а не общие советы. Коммерческая разработка с 2015 года.

Вопросы

Частые вопросы

Ответы на популярные вопросы по теме

Почему сайт может отвечать медленно, если хостинг нормальный?

Потому что время уходит не на сервер как таковой, а на работу кода при каждом показе. В нашем случае соседние проекты на том же сервере отвечали за 0,2–0,3 с, а наш сайт — за 3,05 с. Причиной был один запрос мега-меню в шапке, который выполнялся на каждой странице.

Как отличить медленную сеть от медленного кода?

Снимите время до первого байта для статического файла, например логотипа, и для обычной страницы, по несколько запросов на каждую. Статический файл сайт не рендерит, поэтому его время — это пол сети. Разница между страницей и файлом — это работа вашего сервера и кода.

Где искать запрос, который замедляет все страницы сразу?

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

Кеширование всё решает?

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

Касается ли это OpenCart и других движков?

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

Получайте лучшие статьи на почту

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

Мы уважаем вашу конфиденциальность. Отписаться можно в любой момент.

Ещё в блоге

Похожие статьи

Healthcheck дал 60 % запросов приложения: что показали первые сутки метрикВеб-разработка

Healthcheck дал 60 % запросов приложения: что показали первые сутки метрик

21 сентября 2026 года, в первые сутки учёта запросов по маршрутам, служебный /api/health получил 13 666 запросов — 60 % трафика приложения, и каждый шёл в общую базу. Рассказываем, какие две настройки это убрали, какую цену мы за них платим и как проверить свой healthcheck.

Читать дальше
Сертификаты продлеваются сами: TLS на 116 сайтах и один, который не продлилсяВеб-разработка

Сертификаты продлеваются сами: TLS на 116 сайтах и один, который не продлился

22 сентября 2026 года мы проверили HTTPS-сертификаты на 116 сайтах, которые уже измеряли для рыночных исследований, и для 104 из них сравнили состояние с августовским. Все 116 прошли проверку, 108 стоят на 89- и 90-дневных бесплатных сертификатах, и только у одного сайта сертификат до сих пор не продлился, хотя при типичных настройках уже должен был. Разбираем замеры, границы метода и показываем, как проверить свой сайт одной командой.

Читать дальше
154 ошибки типов, которые выбрасывала сборка: что в них нашлосьВеб-разработка

154 ошибки типов, которые выбрасывала сборка: что в них нашлось

21 сентября 2026 года проверка типов на нашем сайте показала 154 ошибки, хотя сборка каждый раз была зелёной: результат проверки просто выбрасывался. Внутри нашлись нули в статистике ссылок и в экспорте аналитики, сортировка, которая не сортировала, и тесты, которые не запускались. Рассказываем, как разбирали, что изменили и как проверить свой проект.

Читать дальше