Базы данных

MySQL и InnoDB: отличия от PostgreSQL

Половина интернета работает на MySQL. Facebook хранит в нём пользовательский граф из 3 миллиардов людей. Shopify обрабатывает миллион транзакций в пик на MySQL. Зная его внутреннее устройство, можно превратить 10-секундный запрос в 10-миллисекундный.

  • **Shopify**: MySQL + Vitess для шардинга - обрабатывает $500B GMV в год, >1 млн RPS в Black Friday
  • **Twitter**: MySQL для основных данных (твиты, подписки) с multi-datacenter репликацией через binlog
  • **GitHub**: тысячи MySQL серверов под управлением Orchestrator, автофailover за 30 секунд

InnoDB Storage Engine

InnoDB - дефолтный движок MySQL с 2010 года. До него MySQL использовал MyISAM, который не поддерживал транзакции и внешние ключи. Переход на InnoDB был революцией: появился ACID, row-level locking и crash recovery через redo log.

InnoDB хранит данные в **clustered index** - B-Tree, где листовые узлы содержат сами строки, а не указатели на них. Первичный ключ определяет физический порядок данных на диске. Это делает range-запросы по PK молниеносными, но вторичные индексы содержат значение PK как указатель, что добавляет один уровень поиска.

Twitter в 2010-х годах держал основные таблицы твитов на MySQL+InnoDB. При пиковой нагрузке (Super Bowl) они обрабатывали 143,199 твитов в секунду - всё на InnoDB с правильно настроенным buffer pool.

Как InnoDB хранит строки таблицы физически?

MySQL Replication

MySQL replication работает через binary log (binlog) - журнал всех изменений на master. Replica подключается к master, скачивает binlog events и применяет их. Исторически репликация была асинхронной: master не ждёт подтверждения от replica, что давало lag в секунды.

**Semi-synchronous replication** (доступна с MySQL 5.5) гарантирует, что хотя бы одна replica подтвердила получение события перед коммитом на master. Instagram использовал этот режим для защиты от потери данных при падении master.

Airbnb в 2018 году перешёл с асинхронной репликации на semi-sync после инцидента: при падении master replica отставала на 8 секунд, и 8 секунд транзакций были потеряны. После переключения потеря данных при failover стала нулевой.

Что гарантирует semi-synchronous replication в MySQL?

MySQL vs PostgreSQL

MySQL и PostgreSQL решают одну задачу, но с разной философией. MySQL исторически оптимизирован для web-workload: OLTP, простые запросы, горизонтальное масштабирование через репликацию. PostgreSQL - для complex queries, аналитики, extensibility (custom types, functions, FDW).

КритерийMySQLPostgreSQL
MVCCчерез undo log (в InnoDB)через heap + visibility map
JSONJSON тип (5.7+)JSONB с GIN индексами
Full-textFULLTEXT indextsvector + GIN, лучше для RU
Window functionsс 8.0давно, полная поддержка
Репликациявстроенная + ProxySQLstreaming + logical
Кто используетFacebook, Twitter, ShopifyInstagram, Apple, Reddit

Instagram запустился на PostgreSQL, но их ключевая фид-таблица хранит 400 миллиардов строк - они не трогали PostgreSQL, докупали железо. Shopify в 2023 держит MySQL для транзакций (>10000 RPS) и PostgreSQL для аналитики и поисковых фич.

При каком сценарии PostgreSQL даёт преимущество над MySQL?

Clustered Index и его последствия

Clustered index в InnoDB - это не просто индекс, это физический порядок данных. Каждая таблица InnoDB имеет ровно один clustered index (всегда по PRIMARY KEY). Если PK не задан явно, InnoDB создаёт скрытый 6-байтный row ID.

Последствие: **вторичные индексы хранят значение PK**, а не физический адрес строки. При поиске по вторичному индексу InnoDB делает два lookup: сначала в secondary index (получает PK), потом в clustered index (получает строку). Это называется 'double lookup' или 'bookmark lookup'.

Covering index - способ избежать double lookup: если вторичный индекс содержит все нужные колонки, InnoDB не идёт в clustered index. INDEX (user_id, amount) покрывает запрос SELECT amount WHERE user_id = 123 полностью.

Почему UUID как PRIMARY KEY в InnoDB ухудшает производительность INSERT?

GTID: Global Transaction Identifiers

GTID (Global Transaction Identifier) - уникальный идентификатор каждой транзакции в формате `server_uuid:transaction_number`. Введён в MySQL 5.6. До GTID failover был болезненным: нужно было вручную найти позицию в binlog на новом master.

С GTID replica знает, какие транзакции она уже применила. При failover новый master и все replica автоматически синхронизируются - нет нужды указывать `MASTER_LOG_FILE` и `MASTER_LOG_POS` вручную. Это основа для автоматического failover через MHA, Orchestrator или MySQL Router.

GitHub использует Orchestrator + GTID для управления сотнями MySQL серверов. Автоматический failover занимает менее 30 секунд. До GTID failover требовал ручного вмешательства инженера и занимал 5-15 минут.

MySQL устарел и не подходит для высоких нагрузок

MySQL обрабатывает нагрузку Facebook (миллиарды запросов в день) и является основой Vitess - системы управления БД YouTube и Shopify

Предубеждение появилось из-за старого MyISAM и отсутствия некоторых фич SQL-стандарта. InnoDB + современные инструменты делают MySQL production-ready для любых масштабов.

Какую проблему решает GTID при MySQL failover?

Ключевые идеи

  • **InnoDB clustered index** - строки хранятся в B-Tree по PK, монотонный BIGINT PK критичен для производительности INSERT
  • **Binlog репликация** - основа масштабирования чтения; semi-sync гарантирует отсутствие потери данных при failover
  • **GTID** - автоматическая синхронизация replica при смене master, основа для Orchestrator и автоматического failover

Связанные темы

MySQL - база для понимания репликации и шардинга на больших масштабах:

  • Репликация БД — MySQL binlog репликация - классический пример асинхронной репликации
  • Шардинг — Vitess добавляет шардинг поверх MySQL для горизонтального масштабирования
  • Индексы B-Tree — InnoDB использует B-Tree для clustered и secondary индексов

Вопросы для размышления

  • Если таблица orders растёт на 10 млн строк в день, какой тип PRIMARY KEY выбрать и почему?
  • В чём компромисс между асинхронной и semi-synchronous репликацией с точки зрения latency и durability?
  • Когда имеет смысл использовать MySQL вместо PostgreSQL, даже если в проекте уже есть PostgreSQL?

Связанные уроки

  • os-07-memory
MySQL и InnoDB: отличия от PostgreSQL

0

1

Войти