Рубрики
Uncategorized

Исходный код графика туманности объяснил: Rbo

В этой статье мы объясним, как оптимизирован план исполнения. Обзор оптимизатор — это … Tagged с OpenSource, DevOps, Database, Git.

В этой статье мы объясним, как оптимизирован план исполнения.

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

Оптимизатор на основе правил (RBO), который оптимизирует план выполнения в соответствии с предустановленными правилами. Все условия для сопоставления и результаты оптимизации являются относительно фиксированными. Оптимизатор на основе затрат (CBO), который рассчитывает стоимость выполнения различных планов на основе собранной статистики данных, а затем выбирает наименее дорогой план выполнения. До сих пор только RBO был реализован на графике туманности. Поэтому эта статья будет посвящена реализации RBO в графике туманности.

Структура исходных файлов Вы можете найти исходный код оптимизатора в каталоге SRC/Optimizer. Вот структура исходных файлов.

.
├── CMakeLists.txt
├── OptContext.cpp
├── OptContext.h
├── OptGroup.cpp
├── OptGroup.h
├── Optimizer.cpp
├── Optimizer.h
├── OptimizerUtils.cpp
├── OptimizerUtils.h
├── OptRule.cpp
├── OptRule.h
├── rule
│   ├── CombineFilterRule.cpp
│   ├── CombineFilterRule.h
│   ├── EdgeIndexFullScanRule.cpp
│   ├── EdgeIndexFullScanRule.h
|    ....
|
└── test
    ├── CMakeLists.txt
    ├── IndexBoundValueTest.cpp
    └── IndexScanRuleTest.cpp

Справочник по тестированию предназначен для тестирования, каталог правил содержит предустановленные правила, а другие исходные файлы являются исходным кодом для реализации оптимизатора.

В файле src/service/queryinstance.cpp вы можете найти вход в оптимизатор запроса.

Status QueryInstance::validateAndOptimize() {
    auto *rctx = qctx()->rctx();
    VLOG(1) << "Parsing query: " << rctx->query();
    auto result = GQLParser(qctx()).parse(rctx->query());
    NG_RETURN_IF_ERROR(result);
    sentence_ = std::move(result).value();

    NG_RETURN_IF_ERROR(Validator::validate(sentence_.get(), qctx()));
    NG_RETURN_IF_ERROR(findBestPlan());

    return Status::OK();
}

Функция FindBestPlan позволит оптимизатору для выполнения оптимизации, а затем вернет оптимизированный план выполнения.

Процесс оптимизации С топологической точки зрения план исполнения на графике туманности является направленным ациклическим графом. Он состоит из ряда узлов, и каждый узел указывает на свои зависимые узлы. Теоретически, каждый узел может указать выходной узел как вход. Тем не менее, не имеет смысла использовать результат узла, который не был выполнен, поэтому в качестве ввода будут использоваться только выполненные узлы. Кроме того, план выполнения может выполнить некоторые специальные узлы, такие как петли и условные ветви. На рисунке 1 показан план выполнения GO 2 шага от «Тима Дункана».

фигура 1

В настоящее время график оптимизатора в туманности в основном стремится выполнить сопоставление шаблонов в плане выполнения. Если сопоставление будет успешным, будет вызвана соответствующая функция для преобразования соответствующей части плана выполнения в соответствии с предустановленными правилами. Давайте возьмем Гетнигбор -> Ограничить часть плана выполнения в качестве примера. Оператор Limit будет объединен с оператором Getneighbors, чтобы реализовать оптимизацию отжимания для операторов.

Реализация Оптимизатор не работает непосредственно в плане выполнения, но сначала превращает его в OptGroup и OptGroupNode. OptGroup представляет собой одну группу оптимизации, которая обычно относится к одному или нескольким эквивалентным операторам. OptGroupNode представляет независимого оператора и имеет указатели на зависимости и филиалы, что означает, что OptGroupNode сохраняет топологическую структуру плана выполнения. Почему такая структурная трансформация требуется? В основном он стремится абстрагировать топологическую структуру плана исполнения, защитить некоторые ненужные детали выполнения, такие как петли и условные ветви, и облегчить хранение некоторых контекстов в новой структуре для соответствия правил.

Процесс преобразования представляет собой простую обход предварительного заказа, во время которого операторы преобразуются в соответствующую группу OPTGROUP и OPTGROUPNODE. Чтобы облегчить ваше понимание следующего контента, мы называем структуру, состоящую из optgroup и OptGroupNode план оптимизации, который отличается от «плана выполнения».

После преобразования будет начато сопоставление правил и преобразование плана оптимизации. В этом процессе все предварительно определенные правила будут пройдены, и для каждого правила будет выполняться обход снизу вверх по плану оптимизации для сопоставления, что означает, что обход начинается с OptGroup в самом глубоком листовом узле, а затем до этого В корневом узле, но в каждом узле OPTGROUP, сверху вниз выполняется на OptGroupNode внутри, чтобы соответствовать шаблону правила.

Как показано на рисунке 2, шаблоном для сопоставления является Limit -> Project -> Getneighbors. Согласно порядку снизу вверх, сначала выполняется переход сверху вниз на стартовом узле. Поскольку старт не является лимитом, сопоставление не удается. И затем аналогичный сбой сопоставления происходит с узлом Getneighbors до предела. При успешном сопоставлении функция преобразования, определенная в соответствии с правилами, преобразует часть плана оптимизации, который соответствует правилам. Например, на рисунке 2 Limit и Getneighbors будут объединены.

фигура 2

Наконец, оптимизатор преобразует оптимизированный план оптимизации в новый план выполнения. Процесс последнего шага противоположный процессу первого шага, но это также процесс рекурсивного обхода и преобразования.

Добавление новых правил В предыдущих разделах мы представили, как оптимизатор реализован на графике туманности. Однако, если вы хотите добавить правила для оптимизации, понимание слишком большого количества деталей реализации не является необходимым, но требуется знание о том, как определить новое правило. В этом разделе мы возьмем лимитный отжимание в качестве примера, чтобы показать, как добавить новое правило оптимизации. Вы можете найти исходный код правила в SRC/Optimizer/Rule/LimitPushdownRule.cpp.

std::unique_ptr LimitPushDownRule::kInstance =
    std::unique_ptr(new LimitPushDownRule());

LimitPushDownRule::LimitPushDownRule() {
    RuleSet::QueryRules().addRule(this);
}

const Pattern &LimitPushDownRule::pattern() const {
    static Pattern pattern =
        Pattern::create(graph::PlanNode::Kind::kLimit,
                        {Pattern::create(graph::PlanNode::Kind::kProject,
                                         {Pattern::create(graph::PlanNode::Kind::kGetNeighbors)})});
    return pattern;
}
StatusOr LimitPushDownRule::transform(
    OptContext *octx,
    const MatchedResult &matched) const {
    auto limitGroupNode = matched.node;
    auto projGroupNode = matched.dependencies.front().node;
    auto gnGroupNode = matched.dependencies.front().dependencies.front().node;

    const auto limit = static_cast(limitGroupNode->node());
    const auto proj = static_cast(projGroupNode->node());
    const auto gn = static_cast(gnGroupNode->node());

    int64_t limitRows = limit->offset() + limit->count();
    if (gn->limit() >= 0 && limitRows >= gn->limit()) {
        return TransformResult::noTransform();
    }

    auto newLimit = static_cast(limit->clone());
    auto newLimitGroupNode = OptGroupNode::create(octx, newLimit, limitGroupNode->group());

    auto newProj = static_cast(proj->clone());
    auto newProjGroup = OptGroup::create(octx);
    auto newProjGroupNode = newProjGroup->makeGroupNode(newProj);

    auto newGn = static_cast(gn->clone());
    newGn->setLimit(limitRows);
    auto newGnGroup = OptGroup::create(octx);
    auto newGnGroupNode = newGnGroup->makeGroupNode(newGn);

    newLimitGroupNode->dependsOn(newProjGroup);
    newProjGroupNode->dependsOn(newGnGroup);
    for (auto dep : gnGroupNode->dependencies()) {
        newGnGroupNode->dependsOn(dep);
    }

    TransformResult result;
    result.eraseAll = true;
    result.newGroupNodes.emplace_back(newLimitGroupNode);
    return result;
}

std::string LimitPushDownRule::toString() const {
    return "LimitPushDownRule";
}

Чтобы определить правило, первое, что — унаследовать класс Optrule, а затем реализовать интерфейс шаблона, где требуется возвращение шаблона, который необходимо соответствовать. Образец-это композиция операторов и их зависимости, такие как Limit-> Project-> Getneighbors. Следующим, который будет реализован, является интерфейс Transform, который проходит в плане оптимизации для сопоставления. Этот интерфейс проанализирует согласованный план оптимизации в соответствии с предварительно определенным шаблоном, а затем оптимизирует и преобразует план. Например, он объединяет лимитный оператор и оператора Getneighbors, а затем возвращает оптимизированный план оптимизации.

Когда эти два интерфейса реализованы правильно, новое правило оптимизации может работать.

Это все о RBO на графике туманности.

Если вы столкнетесь с какими -либо проблемами в процессе использования графика туманности, пожалуйста, обратитесь к «Руководству по базе данных графика туманности», чтобы устранить задачу. Он подробно записывает точки знаний и конкретное использование базы данных графиков и график туманности базы данных графиков.

Вот ссылка: https://docs.nebula-graph.io/2.5.0/pdf/nebulagraph-en.pdf

Оригинал: «https://dev.to/lisahui/nebula-graph-source-code-explained-rbo-4cjo»