1. Реляционные базы данных – Postgre, Oracle, MS SQL Server и т. д.
2. «Колоночные» базы данных – Vertica, Greenplum, ClickHouse; облачные – Google BigQuery, Amazon Redshift.
3. Файловые – Hadoop.
Я не стал включать в список большие энтерпрайзные системы от IBM, Teradata и других вендоров, у них своя ниша, в которой я не работал.
Лично я работал с Microsoft SQL Server в Ozon.ru и Wikimart.ru, Postgres в Ostrovok.ru, Hadoop в Wikimart.ru и Retail Rocket, Clickhouse в Retail Rocket. У меня остались только положительные впечатления об этих технологиях. В последнее время я предпочитаю экономить и пользоваться открытыми технологиями (open-source).
Итак, реляционные базы данных (рис. 6.2) – рабочая лошадка многих бизнесов. Они все еще популярны, несмотря на атаку NoSQL-технологий. Данные в них хранятся в таблицах с колонками и строками, между таблицами есть «отношения», также можно выставлять логику при операциях с полями и т. д. Оптимизация производительности делается с помощью настройки индексов
Рис. 6.2. Таблицы реляционной базы данных
и различных хаков, которые у каждого вендора свои. Они популярны, с ними умеют работать множество специалистов. Самое главное, что базы этого типа привнесли в мир, – это язык программирования SQL (Structured Query Language). Этот язык может использоваться как для внесения изменений, так и для получения данных. Минус реляционных баз – низкая производительность, когда идет работа с большими данными. И в Ozon.ru, и в Wikimart.ru я держал данные по статистике посещения сайтов в обычной таблице, а это миллиарды строк. Можно было сходить на обед, пока считался нужный запрос.
На помощь реляционным базам данных, в которых данные хранятся построчно [35], пришли колоночные базы. И совершили революцию. Вот пример таблицы реляционной базы (табл. 6.1).
Таблица 6.1. Пример данных реляционной таблицы
Чтобы найти все товары с типом (колонка Type) «Гостиная», придется прочитать все строки данных (если нет индекса по этому столбцу), что удручает, если их миллиарды и даже триллионы. В колоночной базе данные хранятся по столбцам отдельно, отсюда и название – колоночные:
ID: 1 (1), 2 (2), 3 (3)
Name: Стул (1), Стол (2), Стул (3)
Type: Кухонная мебель (1), Кухонная мебель (2), Гостиная (3)
Color: Белый (1), Красный (2), Синий (3)
Теперь, если делать выборку товаров по типу «Гостиная», придется прочитать только нужный столбец. Но как найти нужные записи? Это не проблема: каждое значение столбца содержит номер записи, к которому оно относится. Дополнительно значения столбцов можно отсортировать и даже сжать, что делает такие базы еще быстрее. В них тоже есть минус – требовательность к «железу» сервера, на котором она работает. Колоночные базы идеально подходят для аналитических задач, которые изобилуют запросами по фильтрации и агрегации данных.
Если нужна «молотилка» для совсем больших данных – то это Hadoop. Она была разработана в компании Yahoo, которая сделала эту технологию общедоступной. Эта система работает на распределенной файловой системе HDFS и не требовательна к оборудованию. Для Hadoop компания Facebook разработала SQL-движок под названием Hive, позволяющий писать запросы к данным на языке SQL. Главное преимущество Hadoop – большая надежность. Минус – медленная скорость, зато там, где обычная БД не справится с каким-то запросом, Hadoop доведет дело до конца, медленно, как черепаха, но верно. Я использовал Hive и был доволен результатом, мне удавалось даже писать на нем простейшие алгоритмы рекомендаций.
Теперь главный вопрос – когда и какие технологии использовать?
Мой рецепт следующий:
• Если данных относительно немного и нет таблиц с миллиардами строк, то проще использовать обычную реляционную базу.
• Если данных больше миллиарда строк или требуется хорошая скорость для аналитических запросов (агрегация и выборки) – то лучше всего использовать колоночную базу данных.
• Если требуется хранить очень большой объем с сотнями миллиардов строк, вы готовы мириться с медленной скоростью или хотите иметь архив исходных данных – то Hadoop.
В Retail Rocket использовался Hive поверх Hadoop для службы технической поддержки, но запросы могли выполняться больше получаса. Поэтому требуемые ими данные были переведены в Clickhouse (колоночная база данных), и обработка запросов ускорилась в сотни раз. А скорость очень важна для интерактивных аналитических задач. Сотрудники Retail Rocket мгновенно полюбили новое решение за его скорость. Hadoop при этом остался в качестве рабочей лошадки для расчета рекомендаций.
Как данные попадают в хранилища
Чтобы данные оставались актуальными, их нужно периодически обновлять. Делать это можно путем полного или инкрементального обновления.
Полное обновление применяют к справочникам и состояниям на определенный момент времени (об этих типах я писал в главе 5). Выглядит оно следующим образом – данные скачиваются из источника в промежуточную таблицу или папку (staging) хранилища, и если операция прошла успешно, эти старые данные меняются на свежие. Плюсом такого типа обновления является полное соответствие данных источнику на момент скачивания. Первым минусом является время для обновления таблиц, которое напрямую зависит от размера исходных данных. Второй минус – потеря изменений после обновления данных. Представьте, что у вас есть справочник с товарами магазина, в исходной системе он всегда актуален, а в хранилище обновляется каждый день в полночь. Если какой-то товар был заведен и удален из справочника – вы этого не заметите в хранилище. Для аналитика это будет выглядеть так, будто такого товара не существовало. Заказы этого товара могли совершаться. Поэтому при анализе заказов возникнет ситуация нарушения целостности данных: в таблице этот заказ есть, в справочнике товаров – нет.
Инкрементальное обновление данных применяется для лога изменений (я писал о нем в главе 5). Конечно, можно его полностью перезагружать, но обычно это нецелесообразно из-за большого объема, а следовательно, медленной скорости обновления. Само инкрементальное обновление выглядит следующим образом: система смотрит в хранилище, какие данные были загружены последними (это может быть время или какой-то идентификатор). Далее делается запрос к источнику: «Отдай мне данные, которые поступили после момента X». После получения эти данные добавляются к старым в хранилище. Плюсом инкрементального обновления является скорость. Минусом – возможна рассинхронизация данных, когда были добавлены лишние записи, которые уже были, или, наоборот, произошла потеря данных.