Сравнение MySQL, PostgreSQL и MongoDB

Перевод статьи Comparing MySQL, PostgreSQL, and MongoDB .

При выборе базы данных нужно ориентироваться на несколько факторов:

Поддерживаемые типы данных.

Базы данных поддерживают разные типы данных и от этого зависит то, что вы можете хранить и как можете с этим работать. Примеры типов - это числа (integer), текст (string), бинарная информация (blob) и сложные типы: json или xml. Важно выбрать базу, которая поддерживает нужные вам типы.

Индексирование.

Индексирование улучшает производительность БД улучшая скорость, с которой будет искаться и выдаваться что-то из базы.

Управление параллелизмом.

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

Такие механизмы, как блокировка (запрещает нескольким пользователям одновременно изменять одни и те же данные) и оптимистический конкурентный контроль (даёт одновременный доступ к данным, но проверяет на конфликты, перед изменением данных) помогут работать ббез ошибок.

Масштабируемость.

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

Репликация.

Чтобы данные были всегда доступны, мы делаем репликацию: создаём несколько копий, чтобы в случае недоступности одной базы, данные отдавались из другой.

Соответствие ACID.

ACID (атомарность, согласованность, изоляция, устойчивость) - это набор требований, которые обеспечивают надежную работу БД. Это особенно важно для сфер, в которых согласованность и точность данных имеет большое значение. Например, в финансовых организациях.

А теперь давайте посмотрим на разницу между MySQL, PostgreSQL и MongoDB.

MySQL.

Поддерживаемые типы данных.

MySQL понимает стандартные типы данных, такие как Integer, Float, Varchar, Text. Это даёт возможность хранить множество базовых данных.

-- Creating a table named "users"
CREATE TABLE users(
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100) UNIQUE
);

-- Inserting a record into the "users" table
INSERT INTO users(name, email) VALUES ('John Doe', 'john.doe@example.com');

Индексирование.

MySQL использует несколько типов индекса:

  • Primary key. Уникальный индекс.
  • Unique key. Похож на Primary key, но разрешает одно Null значение.
  • Full-text. Разрешает текстовый поиск.
  • Spatial index. Полезно для пространственных типов данных.
CREATE INDEX idx_username ON users (username);

Параллелизм.

MySQL использует MVCC (управление параллельным доступом посредством многоверсионности).

MySQL использует Multi-Version Concurrency Control (MVCC). MVCC допускает несколько "версий" записи данных, обеспечивая плавную одновременную работу с данными без конфликтов.

Масштабируемость.

MySQL спроектирован для вертикального масштабирования.

Репликация и доступность.

MySQL использует модель "Ведущий-Ведомый". В этой модели основной сервер обрабатывает операции записи, а копии повторяют эти операции у себя. MySQL хорошо подходит для большой нагрузки на чтение. Однако, если основной сервер упадет, то это приведет к единой точке отказа (каскад).

ACID.

MySQL полностью реализует ACID.

PostgreSQL

Поддерживаемые типы данных.

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

-- Creating a table named "users"
CREATE TABLE users(
    id SERIAL PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100) UNIQUE,
    profile_data JSON,
    location POINT,
    ip_address INET
);

-- Inserting a record into the "users" table
INSERT INTO users(name, email, profile_data, location, ip_address) 
VALUES ('John Doe', 'john.doe@example.com', '{"age": 30, "address": {"city": "New York", "state": "NY"}}', POINT(40.730610, -73.935242), '192.168.1.1');

Индексирование.

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

Частичное индексирование.

Этот тип индекса строится по подмножеству строк таблицы, обычно определяемому WHERE. Например, если у вас есть таблица заказов и вы часто запрашиваете отложенные ордера, вы можете использовать частичный индекс для заказов со статусом "в ожидании". Это сделает этот конкретный запрос намного быстрее, и индекс будет занимать меньше дискового пространства, поскольку он применяется только к подмножеству таблицы.

CREATE INDEX idx_partial_orders ON orders (order_id) WHERE status = 'pending';

Индексирование на основе выражений.

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

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

CREATE INDEX idx_expression_orders ON orders (LENGTH(order_text));

Материализованные представления.

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

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

CREATE MATERIALIZED VIEW mat_view_orders AS SELECT * FROM orders WHERE status = 'pending';
CREATE INDEX idx_mat_view_orders ON mat_view_orders (order_id);

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

Параллелизм.

Как и MySQL, PostgreSQL использует Multi-Version Concurrency Control (MVCC), который позволяет одновременно существовать нескольким версиям записи данных, что обеспечивает неблокирующее чтение и запись. Это важно в средах с высокой скоростью транзакций.

Расширяемость.

PostgreSQL более гибок в плане масштабирования и может масштабироваться как по вертикали, так и по горизонтали.

Для горизонтального масштабирования PostgreSQL предоставляет встроенное секционирование и поддерживает сегментирование с помощью таких расширений, как Citus.

CREATE TABLE sales (
    sale_id serial PRIMARY KEY,
    sale_date DATE NOT NULL,
    product_id INT,
    quantity INT
) PARTITION BY RANGE (sale_date);

-- Creating partitions for specific date ranges
CREATE TABLE sales_2022 PARTITION OF sales FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');
CREATE TABLE sales_2023 PARTITION OF sales FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');

Репликация и доступность.

PostgreSQL предлагает ряд решений репликации, как синхронные, так и асинхронные варианты. Например, репликация на основе журналов и репликация на основе операторов. Он также предоставляет различные варианты высокой доступности, такие как "теплый резерв" и "горячий резерв".

Репликация на основе журналов против репликации на основе операторов.

  • Репликация на основе журналов. Это наиболее распространенный метод репликации в PostgreSQL. Изменения данных главных серверов записываются в журнал предварительной записи. Затем копии используют эти журналы для воспроизведения изменений, гарантируя, что они содержат те же данные, что и первичные.
  • Репликация на основе операторов. Вместо репликации результатов транзакции (как при репликации на основе журналов) в копии отправляются SQL-запросы, вызвавшие изменения. Хотя это может быть эффективно для определенных задач, это может привести к несогласованности с недетерминированными функциями (например, NOW() или RANDOM()), поскольку они могут давать разные результаты на основном сервере и копиях.
  • Синхронная репликация: в этом режиме транзакция записи считается завершенной только тогда, когда данные были записаны в основную базу и хотя бы одну копию. Это обеспечивает немедленную консистентность между главным сервером и копией, но может привести к задержке, если операции записи придется ждать подтверждения от копии.
  • Асинхронная репликация: основной сервер не ждет подтверждений от копий. Транзакция считается завершенной, как только данные будут записаны в основную БД, что делает этот метод более быстрым. Однако существует потенциальный риск потери данных, если основной сервер выйдет из строя до того, как копии примут новые данные.

Опции высокой доступности.

  • Теплый резерв: сервер копий работает и постоянно обновляется, используя журналы основного сервера. Однако он не принимает соединения до тех пор, пока не станет основным сервером (обычно, когда основной сервер лежит). Переход от теплого резерва к основному происходит относительно быстро, что обеспечивает минимальное время простоя.
  • Горячий резерв: это улучшенная версия теплого резерва. Копия не просто получает журналы и обновляет свои данные, но и разрешает соединения только для чтения. Это означает, что пользователи могут отправлять запросы на сервер копии даже во время его обновления, обеспечивая балансировку нагрузки и снижая нагрузку на чтение на основном сервере.

ACID.

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

MongoDB.

Поддерживаемые типы.

MongoDB использует модель без схемы, которая позволяет полям содержать данные любого поддерживаемого типа данных, даже в пределах одного документа. Сюда могут входить другие документы, массивы и массивы документов. Это идеально подходит для приложений с непредсказуемыми или гибкими данными.

// Creating a collection named "users"
db.createCollection("users")

// Inserting a document into the "users" collection
db.users.insertOne({
    name: 'John Doe',
    email: 'john.doe@example.com',
    profile_data: {
        age: 30,
        address: {
            city: 'New York',
            state: 'NY'       
        }
    },
    location: {
        coordinates: [-73.935242, 40.730610] 
    },
    ip_address: "192.168.1.1"
});

Индексирование.

Поддерживает различные типы индексов, включая хешированные индексы для шардинга, текстовые индексы для текстового поиска и геопространственные индексы для запроса географических данных.

// Create a hashed index on the 'userId' field
db.users.createIndex({ "userId": "hashed" });

// Create a text index on the 'description' field
db.articles.createIndex({ "description": "text" });

// Create a 2dsphere index on the 'location' field
db.places.createIndex({ "location": "2dsphere" });

Управление параллелизмом.

MongoDB не использует MVCC, но предлагает параллелизм посредством горизонтального масштабирования и секционирования, которое распределяет данные по нескольким серверам. Это помогает балансировать нагрузку и обрабатывать больше одновременных операций.

Масштабируемость.

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

Репликация и доступность.

MongoDB использует модель набора реплик для достижения высокой доступности. Набор копий — это группа серверов MongoDB, поддерживающих один и тот же набор данных. В случае сбоя основного сервера MongoDB обеспечивает автоматическое переключение на резервный сервер.

ACID.

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

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

Проблемы записи: MongoDB позволяет указать, сколько узлов должно подтвердить операцию записи, прежде чем считать ее успешной. Это может варьироваться от основного узла до каждого узла в кластере. Обеспечивая, что определенное количество узлов подтвердило запись, прежде чем считать ее успешной, MongoDB может гарантировать долговечность данных в различной степени. Чем больше узлов необходимо подтвердить, тем выше надежность (но нужно идти на компромисс со скоростью записи).
  • Проблемы записи: MongoDB позволяет указать, сколько узлов должно подтвердить операцию записи, прежде чем считать ее успешной. Это может варьироваться от основного узла до каждого узла в кластере. Обеспечивая, что определенное количество узлов подтвердило запись, прежде чем считать ее успешной, MongoDB может гарантировать долговечность данных в различной степени. Чем больше узлов необходимо подтвердить, тем выше надежность (но нужно идти на компромисс со скоростью записи).
  • Проблемы чтения: MongoDB обеспечивает детальный контроль над операциями чтения. Вы можете установить приоритет свежести данных (частота чтение с основного узла) или высокой доступности, что может включать чтение более старых данных со резервных узлов. Позволяя пользователям контролировать, откуда поступают их данные, MongoDB позволяет им балансировать между чтением самых актуальных данных (согласованность) и доступностью системы.
  • Транзакции: MongoDB (версия 4.0+) поддерживает транзакции с несколькими документами, позволяя выполнять атомарные операции с несколькими документами и даже базами данных. Транзакции с несколькими документами гарантируют, что операции являются атомарными: то есть фиксируются все изменения в транзакции или не фиксируется ни одно. Если транзакция прерывается, ни одно из ее изменений не сохраняется, обеспечивая целостность данных.
  • Повторная запись: если первоначально запись не удалась (например, из-за проблем с сетью), MongoDB пытается еще раз убедиться, что запись произошла, тем самым повышая гарантию того, что после фиксации данные останутся сохраненными.
  • Согласованность сеанса: в рамках одного клиентского сеанса в MongoDB чтения будут отражать предыдущие записи, что гарантирует, что последующие чтения в том же сеансе увидят эту запись после подтверждения записи.

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

О разнице между SQL и NoSQL читайте в этой статье.

Комментариев ещё нет. Оставьте первый!