При оценке баз данных или механизмов вычисления данных вы могли бы наткнуться на такие термины, как поддержка векторизации, запросы времени компиляции или генерация кода, подходящие в соответствии с запросом. Но что они означают? Они что-то значат? Давайте разберемся.
Прежде чем перейти к тому, что, давайте сначала спросим, почему. Зачем нужны векторизованные или скомпилированные запросы? Чтобы ответить на этот вопрос, давайте посмотрим, кто был предшественником векторизованных и скомпилированных запросов. Это будет модель итератора вулкана. . .
Модель итератора вулкана
Представьте себе вулкан, он похож на конус или, по крайней мере, его рисуют так большинство детей, в том числе и я :). Нижеследующее определенно не нарисовано ребенком.
Поскольку форма вулкана предполагает, что лавы (данных) слишком много у основания, и ее дымится из нее очень мало.
Вот определение не-забавной вики:
Модель вулкана (первоначально известная как модель итератора) представляет собой «классическую» стратегию оценки аналитического запроса СУБД: каждый реляционно-алгебраический оператор создает поток кортежей, а потребитель может выполнять итерацию над своими входными потоками. Интерфейс потока кортежей по существу: «открыть», «следующий» и «закрыть»; все операторы предлагают одинаковый интерфейс, и реализация непрозрачна. Каждый вызов «next» создает новый кортеж из потока, если он доступен. Чтобы получить результат запроса, один оператор «следующий-следующий-следующий» в последнем операторе RA; что один, в свою очередь, будет использовать «next» на своих входах для извлечения кортежей, позволяя ему создавать выходные кортежи и т.д. Некоторые «next» будут занимать очень много времени, так как многие «next» для предыдущих операторов потребуются перед они испускают любой вывод. Пример: ВЫБРАТЬ max (v) FROM t; может потребоваться пройти через все t, чтобы найти этот максимум.
Проще говоря для мозга:
Это цепочка итераторов, и данные проходят через них, когда самый верхний итератор вызывает next () на итераторе под ним. Это приводит к распространению вызовов .next () до вызова самого нижнего итератора. Каждый итератор может применять какой-либо предикат или другие операторы. И при визуализации в виде вулкана данные могут уменьшаться по мере продвижения вверх по цепочке итератора.
Что с этим не так?
Ну, на первый взгляд ничего, пока люди не поняли, что это вызывает много промахов кеша инструкций.
Что такое пропуски инструкций в кеше?
Что это за безумие, в которое ты только что вызвался?
Итак, представьте, что ваша база данных использует модель итератора вулкана. Ваши данные находятся на диске, откуда ваш диспетчер дисков считывает их и записывает в основную память по запросу диспетчера буферов. Эта часть информации из основной памяти затем будет загружена в кэш-память (L1 и L2). Из этих кешей информация будет перемещена в регистры, где будут выполняться операции. Однако и данные, и инструкции сборки должны быть загружены в кэш-память.
Итак, у вас есть инструкции и данные, хранящиеся в кеше. Но что, если у вас слишком много инструкций? Ваш запрос был большим, как и сгенерированный код выполнения, который транслировался в большее количество инструкций по сборке. А общий код выполнения запроса привел к большему количеству ветвлений, что привело к увеличению количества бесполезных инструкций в кеше. Но подожди секунду.
Что вы подразумеваете под общим кодом выполнения запроса?
Представьте, что вы пишете код, который поддерживает все виды запросов и все типы данных. Написание такого кода потребует правильного количества абстракций, а также большого количества if-then для обработки различных типов данных.
Пример: написание оператора "больше чем" для механизма выполнения запросов.
Оператору "больше, чем" необходимо знать тип данных. Дата, строки и целые числа приведут к другому ожидаемому поведению и сгенерированным инструкциям по сборке.
Операторы ветвления, как правило, приводят к загрузке инструкций, которые не нужны, потому что эти инструкции никогда не будут выполнены, если условие не выполняется.
Что, если я не напишу общий код, поддерживающий все? Что, если я напишу достаточно кода для моего собственного запроса? Что, если мой механизм выполнения запросов сгенерирует достаточно кода для моего собственного запроса?
Это были вопросы, которые приходили в голову людям, которые впервые задумались о возможности составных запросов.
А что, если такие пропуски кеша инструкций происходят для каждой строки?
В модели вулкана действует каждая строка за раз.
Итак, у нас есть две альтернативы:
- Скомпилированные запросы. Создавайте инструкции с меньшим количеством ветвлений, специфичные для запроса.
- Векторизованные запросы. Допускается пропуск кэша, но не для каждой строки, возможно, для пакета строк.
Итак, теперь мы понимаем, почему были необходимы скомпилированные запросы и векторизованные запросы. Вот и все, а пока мы обсудим векторизованные запросы в части 2, а затем скомпилированные запросы в части 3.
Если вам есть что добавить или вы заметили ошибку в моем сообщении, не стесняйтесь обращаться ко мне, я буду рад внести изменения и кое-что узнать.