В чем разница между MPP и традиционными СУБД?

Часто приходится выслушивать комментарии по поводу того, что «как это так, что СУБД на основе MPP (massive parallel processing) работают настолько быстрее обычных СУБД? У нас же тут самая суперсовременная СХД и супербыстрый сервер с огромным количеством памяти».

Объяснение всему этому очень простое. Рассмотрим простой запрос — что-то типа такого:
select sum(f.amount), c.lastname
from transaction_fact f,  customer c
  where f.date between ’03/01/2013′ and ’03/31/2013′ and f.customerid = c.id
group by c.lastname

То есть, считаем сумму транзакций по каждому клиенту за период в один месяц и объединяем их по категориям клиентов.
Понятно, что если у нас 100 транзакций в месяц и 200 клиентов, то все будет работать быстро. А если 100 миллионов клиентов и 50 миллионов транзакций?

Вот тут начинается самое интересное. Как работает традиционная СУБД? Начитывает (через один, максимум два канала к СХД) все эти 50 миллионов транзакций и начинает производить вычисления.  И, поскольку еще и существует связка по клиентам, то происходит чтение клиентов — и более быстрым с точки зрения СУБД будет использование HASH JOIN — то есть, прочитаются все 100 миллионов клиентов, отсортируются по ID, а потом произойдет выборка по lastname. Почему HASH JOIN, а не NESTED LOOP? Потому, что ходить 50 миллионов раз сначала по индексу, а потом по этому индексу читать запись из таблицы будет заведомо гораздо дольше, чем прочитать сразу всех клиентов и отсортировать.

Конечно, если количество разных клиентов за месяц было не очень большим, то, возможно, NESTED LOOP может оказаться быстрее, но… Во-первых, такая ситуация достаточно маловероятна, а во-вторых, как оценить это «не очень большим», чтобы оценить выгоду одного или другого метода? И, в-третьих, это же еще надо всю статистику правильно собрать, чтобы сделать правильный выбор. В данном случае, эти рассуждения только показывают трудности, с которыми приходится сталкиваться традиционным СУБД. Еще нужно принимать правильные решения: какие данные оставлять в кэше на сервере, какие из него удалять, и т.д.

В итоге, что мы имеем — чтение всех 50 миллионов транзакций и всех 100 миллионов клиентов, сортировка всех клиентов по ID, а потом еще и расчет по всем этим 50 миллионам транзакций с группировкой (которая, естественно, тоже операция весьма дорогая, потому что нужно опять отсортировать результат, хотя и слегка меньшего размера, скажем, в 5 миллионов записей — если считать, что в среднем клиент совершил примерно по 10 транзакций в месяц, но зато уже надо отсортировать по другому полю — по lastname). Очевидно, что все эти чтения с одного, пусть и быстрого, СХД, и разнообразные сортировки и группировки могут быть весьма дорогими и длительными операциями.

Что же происходит в MPP системах?
Рассмотрим простую MPP систему с 16 узлами (это, фактически, минимальная конфигурация для MPP систем). Делает эта MPP система абсолютно то же самое, что и традиционная СУБД — читает все 50 миллионов транзакций и 100 миллионов клиентов, но…

Каждый из этих 16 узлов работает со своими выделенными дисками, то есть чтение этих записей происходит в параллель. Кроме этого, каждый из этих узлов, соответственно, читает в 16 раз меньше записей — приблизительно, по 3 миллиона транзакций. После того, как прочитаны эти транзакции, начинается чтение клиентов, и клиенты читаются, соответственно, тоже в 16 независимых потоков — то есть, приблизительно, по 6 миллионов записей на каждый узел. Дальше еще интереснее. Очевидно, что отсортировать 6 миллионов записей гораздо быстрее, чем 100 миллионов. Каждый узел сортирует свою порцию клиентских записей, а заодно и свою порцию транзакций — по полю customerid.

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

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

В итоге — чтение с дисков происходит в разы быстрее, обработка результатов — тоже, и суммарное время выполнения операции оказывается в десятки, а то и в сотни раз быстрее, чем в традиционных СУБД.

© Михаил Герштейн, команда FLEXTERA BI

Поделиться в соц. сетях

Опубликовать в Google Plus
Опубликовать в LiveJournal
Опубликовать в Мой Мир
Опубликовать в Одноклассники

Добавить комментарий