Что преобразует sql запросы в задания mapreduce
Как прокачать свой SQL до уровня больших данных
Авторизуйтесь
Как прокачать свой SQL до уровня больших данных
Чем отличается SQL в больших данных от обычного SQL? В больших данных используются распределённые вычисления.
Вычисления распределяются между несколькими серверами. Одна база данных находится сразу на нескольких серверах. Результат запроса тоже вычисляется одновременно несколькими серверами. Алгоритмы распределённых вычислений описывает парадигма MapReduce. Давайте разберём, на что это влияет и как прокачать свой SQL до уровня больших данных.
Предупреждение: в данной статье рассматриваются канонические архитектуры обработки данных. Многие современные СУБД и фреймворки построены на их основе и содержат в себе множество доработок и улучшений. Однако набор оптимизаций может отличаться. Поэтому реальная обработка данных на вашем проекте может отличаться в лучшую сторону благодаря именно вашему инструменту. Важно понимать, какие именно оптимизации способен выполнять ваш фреймворк, чтобы правильно контролировать эффективность алгоритмов.
Основы парадигмы MapReduce
Первое, что следует держать в голове, — в больших данных почти любая БД хранит данные на нескольких серверах.
Представим, что у нас есть 3 сервера и таблица клиентов. Вся таблица равномерна распределена на 3 части, каждый сервер хранит 1/3 данных. Чтобы вернуть результат запроса, нужно прочитать каждую часть с каждого сервера и собрать всё на одном сервере, где мы просматриваем результат.
SELECT * FROM CLIENTS
Даже такой простой запрос разбивается на три обязательные части MapReduce:
Каждая из этих операций по-разному распределяется и параллелится, поэтому важно понимать, что они собой представляют.
Подробнее разберём на примерах ниже.
Как писать эффективные SQL-запросы
Вернемся к запросу:
SELECT * FROM CLIENTS
Здесь мы получим равномерное чтение таблицы на трёх серверах. Но что делать с результатом? Если мы захотим вывести его на экран, результат должен быть собран на один сервер, с которого мы выполняем запрос. Получается, что наш последний шаг вывода на экран сводит распределённые вычисления на нет — вся финальная нагрузка придётся на наш сервер, где мы получаем результат.
Стадия Map будет распределённой. Далее последует стадия Shuffle, которая перекинет все данные на один финальный сервер, который должен будет вместить весь результат и вывести его на экран. Если данные настолько большие, что не помещаются на один сервер, даже такой простейший запрос никогда не выполнится. Результирующий сервер всегда будет возвращать ошибку Out of memory.
Схема модели MapReduce
Этот запрос можно достаточно легко изменить:
INSERT INTO CLIENTS_NEW SELECT * FROM CLIENTS
Теперь вместо вывода результата на экран результат будет записан в другую таблицу. Поскольку другая таблица также хранится распределённо, запись могут производить одновременно 3 сервера.
Таким образом, не потребуется собирать все данные в одном месте, все вычисления будут хорошо распределяться. Стадия Map будет хорошо параллелиться, однако теперь стадия Reduce (запись результата) будет выполняться распределённо на тех же серверах, где данные и были прочитаны. Значит, мы можем пропустить стадию Shuffle (не передавать данные между серверами перед записью результата), что тоже ускоряет вычисления.
Данные не собираются на одном сервере
Аналогичная логика применима к операциям с фильтрами, такими как SELECT * FROM CLIENTS WHERE CLIENTS.GENDER = 1 и так далее. Такие фильтры также будут выполняться распределённо на стадии Map.
Операции с агрегациями
Рассмотрим теперь операции с агрегациями. Допустим, мы хотим посчитать количество клиентов по полу.
SELECT COUNT(*) FROM CLIENTS GROUP BY CLIENTS.GENDER
Стадия Map без сюрпризов, снова параллельное чтение тремя серверами. А вот Reduce всё меняет.
Поскольку у нас есть группировка по полу, в ответе мы хотим увидеть два числа — количество мужчин и количество женщин. Значит, на стадии Reduce мы можем задействовать максимум два сервера. Один сервер должен считать всех мужчин, другой — всех женщин. Для этого на стадии Shuffle необходимо передать записи всех мужчин на один сервер, а записи женщин — на другой сервер. Тогда на этапе Reduce результирующим серверам останется только посчитать все записи, полученные на этапе Shuffle.
Мы видим, что Reduce распределяет вычисления в зависимости от группирующих функций. Такая логика применяется для всех агрегатных функций, distinct, join (где группировка идет в зависимости от условия join) и для сортировок.
На стадии Shuffle данные разделяются по указанному признаку
С сортировкой нужно быть особенно аккуратным. Чтобы отсортировать все записи без группировки по ключу, Reduce соберёт все записи на один сервер и будет производить сортировку нераспределённо. Поэтому нужно избегать операций, которые выполняются с неравномерной группировкой (когда группирующих ключей меньше, чем доступных серверов).
Теперь вы знаете, на что нужно обращать внимание при написании запросов к большим данным. Ключ к написанию эффективного запроса — наблюдение за потребляемыми ресурсами БД в зависимости от изменения вашего запроса. Меняйте порядок join, группировок, подзапросы и ищете наилучшее сочетание производительности / нагрузки. Удачи!
Русские Блоги
Углубленный анализ Hive SQL в плане выполнения MapReduce
оглавление
Основная часть статьи проистекает из шедевра Чэнь Чуна на Meituan.com и заслуживает того, чтобы его иметь.оригиналвMeituan техническая командаБыл удален. Некоторое ключевое содержание было разобрано. И добавил немного собственного понимания.
Некоторые картины взяты изRecruit TechnologiesЛомтик:Internal HiveДля тех, кто не понимает, вы можете обратиться к оригинальному тексту (японский).
1. Принцип MapReduce для реализации основных операций SQL
Прежде чем подробно объяснить компиляцию SQL в MapReduce, давайте взглянем на принцип инфраструктуры MapReduce для реализации основных операций SQL
1.1 Принцип реализации Join
Пометьте данные в разных таблицах в выходном значении карты и определите источник данных в соответствии с тегом в фазе сокращения. Процесс MapReduce выглядит следующим образом (здесь только для иллюстрации самой базовой реализации Join, есть другие способы достижения)
1.2 Принцип реализации Group By
Объедините поля GroupBy в значение выходного ключа карты и используйте сортировку MapReduce, чтобы сохранить LastKey в фазе сокращения, чтобы различать разные ключи. Процесс MapReduce выглядит следующим образом (конечно, это только для иллюстрации процесса агрегации без хеширования на стороне сокращения)
1.3 Принцип реализации Отличительного
Если есть несколько различных полей, таких как следующий SQL
Есть два способа достичь:
(1) Если вы все еще используете метод отдельного поля выше, то есть реализацию, показанную на рисунке ниже, вы не можете сортировать отдельно по uid и дате, и вы не можете дедуплицировать через LastKey. Вам все еще нужно дедуплицировать через Hash в памяти во время фазы сокращения.
(2) Во второй реализации все отдельные поля могут быть пронумерованы. Каждая строка данных генерирует n строк данных, затем одни и те же поля будут отсортированы по отдельности. В этом случае во время фазы сокращения необходимо записать только LastKey, чтобы удалить дубликаты.
Эта реализация хорошо использует сортировку MapReduce, сохраняя потребление памяти для дедупликации в фазе сокращения, но недостатком является то, что она увеличивает объем случайных данных. Следует отметить, что при создании уменьшающего значения, за исключением строки, в которой находится первое отдельное поле, поле значения других отдельных строк данных может быть пустым.
2. Процесс преобразования SQL в MapReduce
После понимания основных операций SQL, реализованных в MapReduce, давайте посмотрим, как Hive преобразует SQL в задачи MapReduce. Весь процесс компиляции делится на шесть этапов:
На слайсе шесть этапов выражаются как:
2.1 Phase1 SQL лексический, грамматический анализ
Antlr
Абстрактное синтаксическое дерево (AST Tree)
После лексического и грамматического анализа, если вам необходимо продолжить обработку выражения, используйте грамматику абстрактного синтаксического дерева Antlr в дереве абстрактного синтаксиса, одновременно грамматический анализ преобразуйте входное предложение в абстрактное синтаксическое дерево и затем выполните дальнейший обход синтаксического дерева. Лечение.
Следующая грамматика является правилом грамматики SelectStatement в Hive SQL.Как видно, что SelectStatement содержит такие предложения, как select, from, where, groupby, имея и orderby.
(В следующих правилах грамматики стрелка указывает на переписывание исходного предложения. После переписывания будут добавлены некоторые специальные слова для обозначения конкретной грамматики, например, TOK_QUERY обозначает блок запроса)
Чтобы подробно объяснить процесс перевода SQL в MapReduce, приведем простой SQL в качестве примера, SQL содержит подзапрос и, наконец, записывает данные в таблицу.
SQL генерирует AST Tree (выделение)
Код Antlr для анализа Hive SQL выглядит следующим образом: HiveLexerX и HiveParser являются классами лексического анализа и грамматического анализа, автоматически генерируемыми после того, как Antlr скомпилирует файл грамматики Hive.g и выполняет комплексный анализ в этих двух классах.
Обратите внимание, что внутренний подзапрос также генерирует узел TOK_DESTINATION. Пожалуйста, ознакомьтесь с правилами грамматики SelectStatement выше, этот узел является узлом, который был добавлен специально при переписывании грамматики. Причина в том, что все данные запроса в Hive будут храниться во временном файле HDFS. Является ли это промежуточным подзапросом или конечным результатом запроса, оператор Insert в конечном итоге записывает данные в каталог HDFS, где расположена таблица.
Подробно, после расширения предложения from в подзапросе памяти получается следующее дерево AST: каждая таблица генерирует узел TOK_TABREF, а условие соединения генерирует узел «=». Другие части SQL похожи и не будут подробно описаны.
Посмотрите на пример в срезе:
2.2 Базовый модуль Phase2 SQL QueryBlock
Дерево AST все еще очень сложно и недостаточно структурировано для непосредственного преобразования в программы MapReduce.
QueryBlock (без фокуса)
На следующем рисунке показана диаграмма классов связанных с QueryBlock объектов в Hive, поясняющая несколько важных атрибутов на рисунке.
AST Tree генерирует QueryBlock (выделение)
Процесс генерации QueryBlock с помощью AST-дерева является рекурсивным процессом: сначала он последовательно проходит по AST-дереву, встречается с различными узлами токена и сохраняет их в соответствующих атрибутах. В основном он включает следующие процессы:
Посмотрите на пример в срезе:
2.3 Phase3 логический оператор и дерево логических операторов
Operator
Задача MapReduce, наконец сгенерированная Hive, фаза Map и фаза Reduce состоят из OperatorTree. Логическим оператором является выполнение одной конкретной операции на этапе карты или на этапе уменьшения. Основные операторы включают TableScanOperator, SelectOperator, FilterOperator, JoinOperator, GroupByOperator, ReduceSinkOperator.
Вы можете угадать функцию, выполняемую каждым оператором по имени. TableScanOperator вводит данные исходной таблицы из интерфейса Map платформы MapReduce для управления количеством строк данных в отсканированной таблице. Отметка заключается в получении данных из исходной таблицы. JoinOperator завершает операцию Join. FilterOperator завершает операцию фильтрации. ReduceSinkOperator сериализует комбинации полей на стороне карты в ключ уменьшения / значения, ключ раздела, который может появляться только на этапе карты, а также отмечает конец фазы карты в программе MapReduce, созданной Hive.
Передача данных оператора между этапами Map Reduce является потоковым процессом. После того, как каждый оператор завершает операцию над строкой данных, он передает данные в childOperator для расчета.
QueryBlock генерирует дерево операторов
QueryBlock, генерирующий дерево операторов, должен просмотреть свойства сохраненного синтаксиса объектов QB и QBParseInfo, сгенерированных в предыдущем процессе, включая следующие шаги:
2.4 Оптимизатор логического уровня Phase4
Большинство оптимизаторов логического уровня достигают цели уменьшения MapReduce Job (②) и уменьшения количества данных случайного перемешивания путем преобразования OperatorTree и операторов слияния (①).
Оптимизировать совокупный запрос без выражения GroupBy
MapJoin, нужно предоставить подсказку в SQL, версия 0.11 больше не используется
Агрегирование на стороне карты
Объедините редуктор с тем же ключом разделения / сортировки в линейном OperatorTree
Используйте корреляцию в запросе для объединения связанных заданий, HIVE-2206
2.5 Процесс Phase5 OperatorTree, генерирующий задание MapReduce
Процесс преобразования OperatorTree в MapReduce Job делится на следующие этапы
Этот абзац слишком сложный. Дополнение после обучения снова.
Общая идея такова: начать обход с корневого узла operatorTree. Поместите каждый корневой узел в команду, а затем соберите комбинацию, соответствующую определенным правилам, разделите границы Map / Reduce или разделите границы Job. Есть несколько правил.
Например: при обнаружении TS (QB.aliasToTabs) создается MapWork, а затем встречается с RS (ReduceSinkOperator), он разделяется на MapWork от TS до RS и делится на ReduceWork от RS до следующего RS. Следующий RS генерирует еще один MapWork.
2.6 Оптимизатор физического уровня Phase6
Принцип каждого оптимизатора здесь подробно не описан, но оптимизатор MapJoin представлен отдельно
Что преобразует sql запросы в задания mapreduce
Эрик Фридман, Питер Павловски и Джон Кислевич
Перевод: Сергей Кузнецов
Оригинал: Eric Friedman, Peter Pawlowski, John Cieslewicz. SQL/MapReduce: A practical approach to self-describing, polymorphic, and parallelizable userdefined functions. Proceedings of the 35th VLDB Conference, August 24-28, 2009, Lyon, France
От переводчика
В качестве предисловия, комментария и послесловия к этой статье я написал небольшую заметку «SQL и MapReduce: новые возможности или латание старых дыр?». Возможно, ее первую часть стоит прочитать до чтения перевода.
Содержание
Аннотация
Функции, определяемые пользователями (user-defined function, UDF), – это мощный механизм, позволяющий пользователям расширять функциональные возможности систем баз данных. Несмотря на всю полезность существующих механизмов UDF, в них имеются многочисленные ограничения, включающие требование объявления входной и результирующей схем во время инсталляции и недостаточную возможность распараллеливания выполнения. Мы представляем новый подход к реализации UDF, называемый SQL/MapReduce (SQL/MR) и позволяющий преодолеть многие из этих ограничений. Мы используем идеи парадигмы программирования MapReduce для обеспечения пользователей простым API, с использованием которого они могут реализовать UDF на предпочитаемом ими языке. Кроме того, наш подход обеспечивает максимальную гибкость, поскольку схема результата UDF специфицируется самой функцией во время формирования плана выполнения запроса. Это означает, что SQL/MR-функция является полиморфной. Она может обрабатывать произвольные входные данные, поскольку ее поведение, как и результирующая схема, динамически определяется на основе информации, доступной во время формирования плана выполнения запроса, такой как входная схема функции и специальные параметры, задаваемые пользователями. Это также способствует повторному использованию, поскольку одна и та же SQL/MR-функция может применяться с различными входными схемами и задаваемыми пользователями параметрами.
В этой статье мы описываем побудительные мотивы этого нового подхода к поддержке UDF, а также его реализацию в системе nCluster компании Aster Data Systems. Мы демонстрируем, что в контексте массивно-параллельных систем баз данных без совместно используемых ресурсов эта модель способствует возможности сильно масштабируемых вычислений внутри системы баз данных. Мы также приводим примеры новых приложений, получающих приемущества от использования этой новой инфраструктуры UDF.
1. Введение
Анализ данных постоянно возрастающего объема находится в центре повседневной деятельности и формирования прибыли многих предприятий. Сегодня даже у небольших предприятий накапливаются терабайты данных. Эффективный анализ этих данных может быть ключом к их будущему успеху.
В реляционных СУБД SQL представляется как декларативный язык для манипулирования данными. Однако средства обработки запросов этих СУБД часто не справляются с такой задачей. Аналитики полагают, что SQL слишком сильно ограничивает типы запросов, которые им требуются для извлечения смысла из данных, а те, кто в меньшей степени знаком с декларативным SQL, желают иметь возможность запрашивать данные с использованием более привычных для них процедурных языков. Наконец, в реализациях реляционных СУБД присутствуют несовершенные оптимизаторы запросов, иногда выбирающие неудачные варианты выполнения запросов и не учитывающие варианты оптимизации, специфичные для конкретных прикладных областей. При работе с крупными данными эти неудачные варианты выбора часто обходятся очень дорого, приводя к тому, что выполнение запросов завершается аварийным образом (например, из-за исчерпания рабочей области памяти) или длится недопустимо долгое время, потребляя ценные ресурсы.
Для преодоления этих проблем во многих реляционных СУБД поддерживаются определяемые пользователями функции (User-Defined Function, UDF), в виде которых разработчик может реализовывать задачи с использованием процедурного языка. К сожалению, традиционная инфраструктура UDF разрабатывалась в расчете на один экземпляр базы данных, а параллелизм, если и добавлялся, то задним числом. Это является все более существенным недостатком, поскольку при возрастающих объемах данных требуется применять параллельный подход к обработке и управлению данными с использованием сотен серверов баз данных.
В этой статье мы представляем SQL/MapReduce (SQL/MR), новую инфраструктуру UDF, которая параллельна по своей природе и предназначена для естественного параллельного вычисления процедурных функций на сотнях серверов, работающих вместе как единая реляционная СУБД. Описывается эффективная реализация инфраструктуры SQL/MR в массивно-параллельной реляционной СУБД nCluster компании Aster Data Systems (рис. 1). Представлены примеры приложений, которые стали возможными после появления SQL/MR. Описываемые экспериментальные результаты демонстрируют выигрыш в эффективности, обеспечиваемый SQL/MR по сравнению с «чистым» SQL.
Рис. 1. Общая схема организиции системы баз данных nCluster. Координация системы и запросов производится королевскими (queen) узлами. Данные сохраняются в рабочих (worker) узлах, в которых также производится параллельная обработка запросов. Загрузка данных ускоряется с использованием дополнительных узлов загрузки (loader).
Инфраструктура программирования MapReduce Джеффри Дина (Jeffrey Dean) и Санджая Генавата (Sanjay Ghemawat) [7] делает возможным параллельное вычисление на сотнях серверов. Эта инфраструктура разработана в расчете на использование аппаратных средств массового спроса, и в ней делается упор на отказоустойчивость, что позволяет вычислять задачи, даже если некоторые вызовы завершились аварийно. Инфрастуктура предполагает наличие распределенной файловой системы, в файлах которой находятся обрабатываемые данные, и инфраструктура обеспечивает параллелизацию вычислений над этими данными.
Наша модель совместима с множеством языков программирования, включая управляемые языки (managed language, Java, C#), традиционные языки (C, C++) и скриптовые языки (Python, Ruby).
Эти особенности позволяют реализовывать SQL/MR-функции, как истинно библиотечные функции, работающие над произвольными входными данными; конкретное поведение функций определяется во время обработки запросов, в контексте которых они используются. Это позволяет экспертам разрабатывать мощные функции, которые могут затем использоваться другими людьми в иных контекстах без изменения кода. Инфраструктура SQL/MR и ее реализация делают систему nCluster компании Aster Data дружественной по отношению к приложениям.
Оставшаяся часть статьи организована следующим образом. В разд. 2 обсуждаются близкие по тематике работы. В разд. 3 и 4 рассматриваются синтаксис SQL/MR и реализация инфраструктуры. В разд. 5 демонстрируются некоторые примеры SQL/MR-функций. Экспериментальные результаты, демонстрирующие масштабируемость и производительность SQL/MR-функций, представлены в разд. 6. Разд. 6 содержит заключительные замечания.
1.1 SQL/MapReduce
SQL/MR позволяет пользователям писать собственные функции на любом языке программирования и вставлять их вызовы в запросы, в которых во всех остальных отношениях используются традиционные функциональные возможности SQL. SQL/MR-функция определяется в манере, похожей на способ определения функций map и reduce в среде MapReduce, но в случае SQL/MR эти функции выполняются в контексте базы данных.
Во многих отношениях инфраструктура SQL/MR обеспечивает большие возможности, чем традиционные механизмы UDF. Наиболее важно то, что по умолчанию SQL/MR-функции являются параллельными. Как будет показано в разд. 3, модель исполнения SQL/MR-функций (обеспечиваемая их API, на особенности которого повлиял подход MapReduce) является параллельной по своей сути. Запросы выполняются параллельно на крупных кластерах, что обеспечивает линейную масштабируемость системы при возрастании объема данных. Мы продемонстрируем это в разд. 6. SQL/MR-функции также являются динамически полиморфными и самоописываемыми. На практике это означает, что входные схемы SQL/MR-функций определяются неявно во время обработки запросов, а результирующие схемы определяются программным образом самими функциями во время выполнения запроса. Кроме того, в вызов SQL/MR-функции во время выполнения запроса могут быть включены разделы специальных аргументов, обеспечивающих дополнительный динамический контроль над поведением функции и схемой. Эти особенности позволяют реализовывать SQL/MR-функции как истинно библиотечные функции, работающие над произвольными входными данными; конкретное поведение функций определяется во время обработки запросов, в контексте которых они используются. Сложный аналитический код может разрабатываться экспертами и затем использоваться другими людьми в иных потоках работ без каких-либо изменений. Детали синтаксиса SQL/MR и реализация инфраструктуры описываются в разд. 3 и 4.
Мы продемонстрируем некоторые преимущества SQL/MR на примере формирования данных о пользовательских сессиях на основе журнальных файлов Web-сайтов (clickstream sessionization). Большее число примеров можно найти в разд. 5 и 6.
1.2 Формирование данных о пользовательских сессиях на основе журнальных файлов Web-сайтов
Разбиение на сессии можно выполнить с использованием SQL, но SQL/MR позволяет упростить это действие и повысить его эффективность. В SQL/MR-функции для этого разбиения требуется только один проход по таблице кликов, в то время как при выполнении SQL-запроса потребуется дорогостоящее соединение этой таблицы с ней же самой. Кроме того, динамический полиморфизм SQL/MR-функции позволяет повторно использовать ее для вычисления информации о сессиях над таблицами с любой схемой. Таким образом, SQL/MR-функция для разбиения на сессии становится повторно используемой библиотечной подпрограммой, которую может использовать любой аналитик.
Сначала мы покажем использование SQL/MR-функции sessionize в запросе над таблицей кликов с рис. 2, а потом опишем реализацию самой функции.
2. Родственные работы
Определяемые пользователями функции и процедуры – это давнишние средства СУБД, позволяющие расширять их функциональные возможности. Подобно тому, как определяемые пользователями типы (user-defined type, UDT) позволяют приспособить к потребностям пользователей то, что сохраняется в базе данных (см., например, [19]), определяемые пользователями функции дают возможность индивидуализировать то, как в системе баз данных обрабатываются данные [18, 11, 6, 20, 21, 22, 4, 12]. Оптимизации способов выполнения запросов к базе данных, содержащих вызовы UDF, посвящались серьезные исследования; см., например, [6, 11, 10]. Но большая этих работ выполнялась в контексте одного экземпляра базы данных, и в них почти не затрагивались аспекты параллельного выполнения UDF в параллельной СУБД без совместно используемых ресурсов.
Проводились некоторые исследования, посвященные определяемым пользователями агрегатам, скалярным функциям [14] и табличным операциям [15]. Традиционные определяемые пользователями агрегаты могут выполняться параллельно при наличии определяемых пользователями локальной и глобальной функций завершения вычислений (finalize function) [14]. Тогда частичные агрегаты вычисляются параллельно, а затем глобально завершается вычисление общего агрегата. Параллельные скалярные функции без состояния параллелизуются тривиально. Для другого класса скалярных функций, таких как «скользящее среднее» (moving average), требуется поддержка некоторого состояния, но если пользователь явно указывает способ разделения, то система может разделить данные и выполнить вычисление параллельно [14]. В качестве следующего шага в [15] предлагаются определяемые пользователями табличные операции, в которых, аналогично аргументам и результатам SQL/MR-функций, отношениями являются и аргументы, и результаты. При определении табличных операций пользователь должен статически предоставить системе стратегию разделения, чтобы сделать возможным параллелизм и проинформировать систему о том, как можно использовать соответствующую операцию. При определении SQL/MR-функций явный или статический выбор способа разделения или использования функции не требуется – эта информация определяется во время обработки запроса на основе контекста использования SQL/MR-функции.
В последнее время возрастает интерес к инфраструктурам распределенной параллельной обработки данных. К числу примеров относятся MapReduce компании Google [7], Dryad компании Microsoft [13], и проект с открытыми исходными текстами Hadoop [1]. Эти инфраструктуры обеспечивают мощные средства параллельной обработки данных, поскольку от пользователей требуется всего лишь реализация строго определенных процедурных методов. После этого инфраструктура управляет параллельным выполнением этих методов в крупных кластерах серверов. Основное преимущество таких систем состоит в том, что разработчикам требуется писать лишь простые процедурные методы, которые затем применяются параллельно с использованием строго определенной процедуры разделения и агрегации данных. Недостаток этих инфраструктур заключается в том, что разработчикам часто приходится писать код для выполнения задач, которые могут быть легко выражены на SQL или другом языке запросов. В частности, ограничивается повторное использование кода для непредвиденных запросов, поскольку отсутствует язык более высокого уровня, чем процедурный код.