Статьи

Гибкая схема MongoDB: как исправить усиление записи

Первоначально Написал  Стефан Комбоудон

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

Напишите усиление?

Связь между схемой и усилением записи не очевидна с первого взгляда. Итак, давайте сначала посмотрим на таблицу в реляционном мире:

mysql> SELECT * FROM user LIMIT 2;
+----+-------+------------+-----------+-----------+----------------------------------+---------+-----------------------------------+------------+------------+
| id | login | first_name | last_name | city      | country                          | zipcode | address                           | password   | birth_year |
+----+-------+------------+-----------+-----------+----------------------------------+---------+-----------------------------------+------------+------------+
|  1 | arcu  | Vernon     | Chloe     | Paulista  | Cook Islands                     | 28529   | P.O. Box 369, 1464 Ac Rd.         | SSC44GZL5R |       1970 |
|  2 | quis  | Rogan      | Lewis     | Nashville | Saint Vincent and The Grenadines | H3T 3S6 | P.O. Box 636, 5236 Elementum, Av. | TSY29YRN6R |       1983 |
+----+-------+------------+-----------+-----------+----------------------------------+---------+-----------------------------------+------------+------------+

Поскольку все записи имеют одинаковые поля, имена полей хранятся один раз в отдельном файле (файл .frm). Таким образом, имена полей — это метаданные, а значение каждого поля для каждой записи — это, конечно, данные.

Теперь давайте посмотрим на эквивалентную коллекцию в MongoDB:

{
        {
                "login": "arcu",
                "first_name": "Vernon",
                "last_name": "Chloe",
                "city": "Paulista",
                "country": "Cook Islands",
                "zipcode": "28529",
                "address": "P.O. Box 369, 1464 Ac Rd.",
                "password": "SSC44GZL5R",
                "birth_year": 1970
        },
        {
                "login": "quis",
                "first_name": "Rogan",
                "last_name": "Lewis",
                "city": "Nashville",
                "country": "Saint Vincent and The Grenadines",
                "zipcode": "H3T 3S6",
                "address": "P.O. Box 636, 5236 Elementum, Av.",
                "password": "TSY29YRN6R",
                "birth_year": 1983
        }
}

Одно отличие от таблицы в реляционном мире состоит в том, что MongoDB не знает, какие поля будут в каждом документе. Поэтому имена полей — это данные, а не метаданные, и они должны храниться вместе с каждым документом.

Тогда возникает вопрос: насколько велика нагрузка на дисковое пространство? Чтобы иметь представление, я вставил 10M таких записей в таблицу InnoDB (добавив индекс по паролю и на birth_year, чтобы таблица выглядела как настоящая таблица): размер на диске составляет около 1,4 ГБ .

Я также вставил те же 10M записей в коллекцию MongoDB, используя обычный механизм хранения MMAPv1, снова добавив индекс по паролю и birth_year, и на этот раз размер на диске… 2.97 ГБ !

Конечно, это не сравнение яблок и яблок, поскольку формат хранения InnoDB и формат хранения MongoDB не идентичны. Однако разница в 100% все еще значительна.

компрессия

Один из способов справиться с усилением записи — использовать сжатие. В MongoDB 3.0 доступен механизм хранения WiredTiger, одним из преимуществ которого является сжатие (алгоритм по умолчанию: snappy ). Percona TokuMX также имеет встроенное сжатие с использованием zlib по умолчанию.

Перестройка коллекции с 10M документами и двумя индексами теперь дает следующие результаты:
WiredTiger: 1.14GB
TokuMX: 736MB

Это сокращение размера данных в 2,5-4 раза, очень хорошо!

WiredTiger также обеспечивает сжатие zlib, и в этом случае сбор составляет всего 691 МБ . Однако загрузка ЦП намного выше по сравнению с snappy, поэтому zlib можно использовать не во всех ситуациях.

Вывод

Конструкция без схемы в MongoDB привлекательна, но имеет несколько компромиссов. Усиление записи является одним из них, и использование WiredTiger с MongoDB 3.0 или Percona TokuMX является очень простым способом решения этой проблемы.