Обновить
16K+

MySQL *

Свободная реляционная СУБД

31,81
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

1.5 миллиона событий в день и ни одной таблицы events: как мы считали продуктовую аналитику 300K-бота по голому проду

Уровень сложностиСложный
Время на прочтение16 мин
Охват и читатели5.8K

Маркетолог прислал мне скрин дашборда и одно слово: «пусто».

На скрине — панель «Количество пришедших по реферальной ссылке за период». Ноль. Под ней — график регистраций. Тоже ноль. Ссылка, по которой он пришёл, вела на дашборд с фильтром по конкретному slug — тому самому, который он неделю крутил в закупке.

Я открыл ту же ссылку, поменял в урле from=now-6h на from=now-30d и увидел 16 регистраций.

Дефолтный интервал в Grafana — 6 часов. У бота ночью в этой гео никого нет. Аналитика работала идеально и показывала абсолютно честный ноль.

Это самая безобидная из историй, которые тут будут. Дальше — про то, как мы строили продуктовую аналитику для Telegram-бота с AI-персонажами на ~300K MAU, ~75 RPS в пике и ~1.5M событий в день: без ClickHouse, без Amplitude, без единой event-таблицы. Двенадцать дашбордов в Grafana поверх боевой MySQL. Три из них какое-то время врали, и это выяснилось не сразу.

Главный парадокс всего проекта помещается в одну строку: через систему проходит полтора миллиона событий в день, и ни одно из них не записано как событие. Есть только строки в продуктовых таблицах и их created_at. Всё, что вы прочитаете ниже, — следствие этого факта.

Статья — не туториал «подключите MySQL к Grafana за 10 шагов». Это разбор того, что происходит, когда продуктовые метрики приходится доставать из схемы, которую проектировали под продукт, а не под аналитику, — и когда по этим метрикам прямо сейчас решают, лить трафик дальше или нет.

Дисклеймер: проект под NDA, поэтому названия, точные объёмы и часть деталей изменены. Порядок величин, схема и сами проблемы — настоящие.

Читать далее

Новости

Как KupujemProdajem ищет по 5,6 миллиона объявлений примерно за 10 мс с помощью Manticore Search

Время на прочтение6 мин
Охват и читатели6.4K

Как крупнейшая площадка объявлений Сербии использует Manticore Search, чтобы искать по 5,6 миллиона активных объявлений примерно за 10 мс, обновлять индекс в реальном времени и готовиться к гибридному поиску.

Читать далее

За полгода мы проанализировали 7,79 млн SQL-запросов: какие СУБД и версии встречались чаще

Время на прочтение1 мин
Охват и читатели6.3K

За первое полугодие 2026 года мы проанализировали 7,79 млн SQL-запросов с нескольких тысяч серверов. В статье описали распределение по семействам СУБД и major-версиям.

Читать далее

Меня подняли на смех за ответ про VIEW. Я поднял MySQL 8.4 и PostgreSQL 17 и померил

Уровень сложностиСредний
Время на прочтение12 мин
Охват и читатели26K

На одном собеседовании меня спросили про VIEW. Я ответил честно: в живых проектах они мне почти не попадались; для агрегатов надёжнее держать отдельную таблицу; а сами представления - вещь настолько нишевая, что за карьеру пригождались считанные разы. Разделение прав, долгие миграции, совместимость со старым ПО - вот и весь список. Ответ приняли прохладно. Один из собеседников сказал: “Ничего ты не понимаешь во VIEW” - и все посмеялись.

Прошло много времени. VIEW в моём коде так и не прибавилось, а вопрос остался, а вдруг с тех пор всё изменилось? Движки вышли новые. Поэтому я поднял MySQL 8.4 и PostgreSQL 17, залил одинаковые данные и прогнал основные сценарии один за другим.

Читать далее

Как уронить базу данных

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели8.6K

Так получилось, что пару десятилетий занимался в тои числе и базами данных. Ставил. Тюнил. Выносил логику В базу. Вынос иллогику ИЗ базы. Поднимал когда падали... Когда перешёл в большой SRE‑спорт, почти октаду лет поддерживал экзабайтные аналитические query engine. В общем, развлекался, как мог.

Главное открытие заключалось в том, что почти всё, что считается невозможным, случается. Люди креативны. Ты им дашь регексп — и они начнут майнить биткойны. Ты им дашь data lake — и они начнут хранить данные в именах таблиц. Ты им дашь GEO... Сам виноват.

Но самое интересное в том, что есть пласт проблем, который лежит совсем не в области современных сверхсложных методов параллелизации обработки, а в наследии 80ых годов прошлого века. То, что никого раньше не волновало, внезапно стало вызывать сбои. Причём в самом лучшем их проявлении — всё работает, клиент доволен, система растёт, цветёт и пахнет. А в один внезапный день запросы не работают, сервер падает, и что делать непонятно, так как никто ничего не менял.

И это ещё хороший сценарий, так как никто ничего плохого и не хотел: можно поймать запрос, заблокировать, и спокойно разбираться.

Роняем

Cделал бесплатный чат для сайта с функциями платных сервисов, делюсь

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели9.7K

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

Читать далее

Как не начать кодить слишком рано?

Уровень сложностиПростой
Время на прочтение6 мин
Охват и читатели7.2K

Часто разработка начинается с кода. Есть идея - мы открываем IDE, создаём проект и начинаем писать. Не задумываясь о том, что в этот момент мы ещё можем не понимать, какую проблему решаем и что вообще должна делать система.

В этой статье разберём путь от пользовательской потребности до реализации: UCD → FR/NFR → KISS → компонентная разработка → код.

Читать далее

UUID в Manticore: практическое руководство

Время на прочтение9 мин
Охват и читатели8K

В обзорной статье мы разобрали, зачем использовать в поиске тот же UUID, что и в основной базе (если таковая имеется). Здесь сразу перейдём к практике: создадим таблицу, выполним основные операции через SQL и JSON API, а затем загрузим несколько документов через /bulk.

Все примеры рассчитаны на Manticore Search 28.5.0 или новее. Значение <generated UUID> в ответах обозначает UUID, который Manticore создаст при обработке запроса. Копировать эту строку в следующий запрос не нужно: подставьте фактический id из своего ответа.

Читать далее

UUID в Manticore: единый ID для основной БД и Manticore

Время на прочтение5 мин
Охват и читатели9K

Допустим, у вашего товара в основной базе уже есть ID 550e8400-e29b-41d4-a716-446655440000. Он попадает в события, логи и ответы API. Но при загрузке того же товара в Manticore приложению приходится выдавать ему ещё один, числовой ID.

До Manticore Search 28.5.0 ID документа был беззнаковым 64-битным числом. UUID можно было сохранить в отдельном строковом атрибуте, однако идентификатором документа он от этого не становился. Для UPDATEREPLACE и DELETE всё равно требовался числовой id.

В результате приходилось хранить соответствие между UUID из основной БД и числовым ID в таблице Manticore. Теперь без него можно обойтись: RT-таблица Manticore умеет использовать UUID как ID документа.

Читать далее

Я написал мессенджер в одиночку. Поможете устроить ему краш‑тест?

Уровень сложностиПростой
Время на прочтение6 мин
Охват и читатели24K

Дисклеймер: Это статья-проверка на прочность. Проект работает на PHP + MySQL + Polling каждые 3 секунды. Если вы кликнули по ссылке, а сервер отдаёт 502 или упорно молчит — значит, поллинг взял своё под нагрузкой Хабра, а я прямо сейчас судорожно оптимизирую запросы и чиню базу!

Привет, Хабр!

Я в одиночку разработал web‑мессенджер Conlink Messenger. Его главная фича — полный отказ от привязки к номеру телефона: только email, пароль и никакого сбора персональных данных.

Я долго откладывал публикацию в ожидании «идеального кода», но понял, что этот момент никогда не наступит. Поэтому выкатываю MVP в том виде, какой он есть — с простой архитектурой, поллингом вместо WebSocket и кучей спорных решений.

Если после этой статьи окажется, что половину backend'а стоит переписать — значит, опубликовал не зря. Приглашаю устроить проекту честный краш‑тест!

Узнать, как устроен Conlink →

Фасетный поиск с активными фильтрами

Время на прочтение10 мин
Охват и читатели6.1K

Фасеты в интернет-магазине кажутся простыми до первого выбранного фильтра.

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

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

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

В Manticore Search 25.12.0 появился facet_filter_mode, который переносит это поведение в API фасетов. Теперь в запросе можно описать, как ведёт себя панель фильтров магазина, а приложению не нужно вручную собирать почти одинаковые запросы для каждого фасета.

Читать далее

Meilisearch и Manticore Search: проверяем сравнение на практике

Время на прочтение12 мин
Охват и читатели6.9K

Несколько дней назад Meilisearch опубликовал сравнение с Manticore Search . Мы тоже любим сравнения: в 2023 году опубликовали своё с воспроизводимыми бенчмарками. Сразу оговоримся: мы спорим не со всей статьёй. Часть выводов Meilisearch справедлива, а кое-где сравнение говорит в пользу Manticore Search.

Однако часть сведений о Manticore Search уже устарела. Спорить в теории мы не стали: запустили актуальные версии обоих движков (Manticore Search 28.4.4 и Meilisearch 1.41/1.48) и повторили описанные сценарии. Ниже мы приводим команды и ответы обоих движков, чтобы проверку можно было повторить самостоятельно.

Читать далее

Текстовая MMO RPG на движке форума Invision 5 с PWA приложением и кубиками

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели8.3K

Привет, Хабр! Текстовые браузерные MMO вроде старой «Тюряги онлайн» — жанр древний, но до сих пор живой, особенно среди фанатов олдскульных вселенных. В сообществах готоманов нашу игру уже смело окрестили «Тюрягой онлайн 2.0», и сходство тут прямое: и там, и там на бэкенде крутится суровый выживач на зоне. Только в Тюряге ты обычный зэк на нарах, а Миненталь — это колония под магическим барьером, где каждый кусок мяса падальщика на счету. Игрок либо ходит на охоту и пашет на фракцию, либо быстро отбросит коньки в канаве от голода или первого же каторжника.

Когда мы на Бесте с нашими технарями задумали сделать эту тактическую RPG «Путь Героя», пришлось выбирать платформу для серверной части. В итоге мы решили использовать наш старый форум ещё времён 2004 года, обновив его с древней версии 3.4.6 до свежего каркаса IPS 5. Из коробки у него есть всё, что нужно: нормальная система прав, готовая база пользователей и вменяемое API. Но чтобы превратить обычный форум в нормальную игру, пришлось знатно поковыряться под капотом и в базах. Первым делом нужно было решить две главные проблемы: как упаковать всё это дело в легкое мобильное приложение и раз и навсегда отвадить игроков от читерства с кубиками.

Читать далее

Ближайшие события

Интерактивный CLI-менеджер процессов MySQL на асинхронном Python

Уровень сложностиПростой
Время на прочтение3 мин
Охват и читатели7.8K

При разработке проектов на небольших VPS часто возникает ситуация, когда процесс mysqld загружает процессор на 100%. Обычно в такие моменты приходится заходить по SSH, открывать консоль бд и вручную вводить SHOW FULL PROCESSLIST;, чтобы найти тяжелый запрос и завершить его через KILL. Если запросов много, делать это вручную через стандартный вывод не всегда удобно.

Это легковесный интерактивный CLI - менеджер процессов, который работает на базе асинхронного драйвера aiomysql. Он опрашивает системную таблицу information_schema.processlist и выводит текущую активность в терминал в виде таблицы, позволяя управлять потоками СУБД.

Читать далее

Миграция MariaDB → PostgreSQL без даунтайма: почему обычные утилиты не подошли и как мы сделали это через Debezium

Уровень сложностиСредний
Время на прочтение9 мин
Охват и читатели8.3K

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

В этой статье - как мы решали эту задачу для интернет-магазина на MariaDB, почему готовые консольные конвертеры не годятся для «живой» миграции, и как выглядит рабочая схема на Debezium + Kafka Connect, включая Ansible-роль для повторяемого запуска.

Читать далее

Ваш бэкап не восстановится. Вы просто ещё об этом не знаете

Уровень сложностиПростой
Время на прочтение6 мин
Охват и читатели8.1K

Крон отработал. Экзит-код ноль. Файл лежит в S3, размер похож на правду. Мониторинг зелёный. Всё говорит о том, что бэкап сделан успешно, вот только его никогда не пробовали восстановить.

Я лично сталкивался с этой проблемой дважды и один раз наблюдал её последствия в масштабах всего интернета. Это побудило меня создать инструмент, который регулярно восстанавливает бэкапы по расписанию и проверяет целостность данных. Ниже я расскажу, почему «бэкап снят» и «бэкап восстановится» — это два совершенно разных факта, а также как автоматическая проверка второго факта работает на практике.

Читать далее

Я собрал кнопку, которая сотрёт прогресс всех моих игроков. И до сих пор боюсь её нажать

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели8.7K

Два года по вечерам в одиночку пилю текстовую MMORPG в Telegram. Сейчас в ней 1111 аккаунтов и 586 выживших, которые бродят по мрачному острову. И где-то в админке ждёт кнопка, которая сотрёт их прогресс до нуля. Сезонный вайп, как в Rust. Я собрал её, проверил на тестовом сервере и до сих пор не нажал на проде. Рассказываю, почему «стереть всех» это не DELETE FROM, как один разработчик не держит в голове 99 таблиц, и какой тест блокирует мне деплой, если я забыл про новую таблицу.

Читать далее

Ускоряем импорт цен и остатков в 1С-Битрикс: от часов к секундам

Уровень сложностиСредний
Время на прочтение4 мин
Охват и читатели5.7K

Стандартный обмен данными в 1С-Битрикс часто превращается в ночной кошмар: полная выгрузка остатков на больших каталогах может занимать от 1 до 8 часов. Когда бизнес требует обновлять данные каждые 15 минут, штатные методы API и XML-импорт просто перестают справляться.

В этой статье я покажу, как с помощью прямого SQL запроса и временных таблиц в памяти (ENGINE=MEMORY) ускорить импорт в сотни раз. Это реальный кейс с продакшена, который стабильно работает уже 4 года на проекте с миллионом товаров и десятками складов.

Читать далее

MySQL под Хабраэффектом: кастомный асинхронный Connection Pool на Py, который экономит 80% RAM сервера

Уровень сложностиСредний
Время на прочтение2 мин
Охват и читатели11K

Каждый бэкенд-разработчик рано или поздно сталкивается с ситуацией, когда база данных MySQL внезапно ложится при резком пиковом наплыве пользователей. Классическая ошибка на старте - создавать новое независимое соединение с СУБД на каждый чих приложения, выполнять один короткий запрос и закрывать коннект. Когда на сайт одновременно залетают сотни людей, сервер моментально упирается в системный лимит max_connections и падает с ошибкой OperationalError: (1040, 'Too many connections'), попутно забивая всю доступную оперативную память.

Читать далее

Интернет или ничего: как заставить PHP-разработчика ERP-системы писать под Windows

Уровень сложностиСредний
Время на прочтение9 мин
Охват и читатели5.8K

"Если вашего бизнеса нет в Интернете, то вас нет в бизнесе! Скоро на рынке останется два вида компаний: те, кто в Интернете и те, кто вышел из бизнеса." 

А потом вдруг интернета не стало и нужно было срочно что-то придумать для работы нашей ERP-системы оффлайн

Что попробовали и что получилось
1
23 ...