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

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

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

16 сентября 2026 г.
8 мин чтения

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Аналитика

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

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

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

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

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

https://lionex.com.ua/blog/chomu-storinka-dumala-try-sekundy

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

9 мин
22 сент.
Читать дальше