BI Consult Desktop Logo BI Consult Mobile Logo
  • Russian BI Исследование российских bi
  • Перейти на Fine BI
  • Контакты
  • +7 812 334-08-01
    +7 499 608-13-06
  • Отправить сообщение
  • Главная
  • Продукты Эксперт-BI
    • Дистрибуция
    • Розничная торговля
    • Производство
    • Операторы связи
    • Страхование
    • Банки
    • Лизинг
    • Логистика
    • Нефтегазовый сектор
    • Медицина
    • Сеть ресторанов
    • E-Commerce
    • Сельское хозяйство
    • Энергетика
    • FMCG
    • Девелоперы
    • Маркетплейсы
    • Пищевая промышленность
    • Фармацевтика
    • Построение Data Platform
    • Цифровая трансформация
    • Управление по KPI
    • Финансы
    • Продажи
    • Склад
    • HR
    • Маркетинг
    • Внутренний аудит
    • Категорийный менеджмент
    • S&OP и FP&A
    • Геоаналитика
    • Цепочки поставок (SCM)
    • AutoML
    • Process Mining
    • IBP
    • ИТ (CIO)
    • Закупки
  • Платформы
    • Системы бизнес-анализа (BI)
    • Интегрированное бизнес-планирование (IBP)
    • Хранилища данных (DWH / Lakehouse)
    • Каталоги данных (Data Catalog)
    • Системы ETL и ELT
    • AI / Исскуственный интеллект
    • Шина данных (ESB)
    • Система управления мастер-данными (MDM)
    • Семантический слой
  • Услуги
    • Переход на отечественные BI и DWH системы
    • Консалтинг
    • Пилотный проект
    • Обучение и сертификация
    • Бесплатное обучение
    • Поддержка
    • Технические задания
    • Сбор требований для проекта внедрения BI-системы
    • CI/CD для DWH
    • Аудит BI приложений и DWH
    • Выделенная команда
    • Настойка и поддержка баз данных
    • Разработка BI Стратегии
    • Styleguide для BI-системы
    • Как выбрать BI-систему
  • Курсы
    • Учебный курс Информационная грамотность (Data Literacy)
    • Учебный курс для бизнес-аналитиков
    • Учебный курс для системных аналитиков
    • Учебный курс по Data Governance
    • Учебный курс Как стать CDO
    • Учебный курс Современная архитектура хранилища данных
    • Учебный курс по Fine BI
    • Учебный курс по FineReport
    • Учебный курс по DWH
    • Учебный курс по Data Science (ML, AI)
    • Учебный курс по PostgreSQL
    • Учебный курс по Greenplum
    • Учебный курс по Apache Airflow и NiFi
    • Учебный курс по Open-source BI
    • Учебный курс по ClickHouse
    • Учебный курс по DataLens
    • Учебный курс по Loginom
    • Учебный курс по Modus BI и ETL
    • Учебный курс по Visiology
    • Учебный курс по dbt (Data Build Tool)
  • Компания
    • Руководство
    • Новости
    • Клиенты
    • Карьера
    • Скачать
    • Контакты

BI

  • FineBI
  • FineReport
  • FineDataLink
  • FineChatBI (FineAI)
  • Коннекторы данных из 1С в BI
  • Airflow / Nifi
  • Visiology
  • PIX BI
  • Modus BI
  • Yandex.DataLens
  • Open-source BI: Superset/Metabase
  • Luxms BI
  • AW BI + Alpha BI
  • FlyBI + Форсайт. Аналитическая Платформа
  • Loginom
  • Триафлай
  • AI / Исскуственный интеллект
  • Optimacros
  • Навигатор BI
  • Семантический слой

СУБД

  • Arenadata
  • ClickHouse
  • Greenplum
  • Postgres Professional
  • TData

Другое

  • Построение Data Platform
    • Аналитическое хранилище данных
    • Data Lake и Data Engineering
    • Подробнее про Data Lake
    • Внедрение Lakehouse
      • Apache Doris
      • StarRocks
      • Trino
    • Миграция витрин из пропиетарных DWH на новый стек
    • Учебный курс "Современная архитектура хранилища данных"
Главная » Курсы по системам бизнес-анализа и методологии » Учебный курс по PostgreSQL » Как устроен PostgreSQL » Обработка запросов в PostgreSQL - обзор

Обработка запросов в PostgreSQL - обзор

Несмотря на то, что в версии 9.6. реализована возможность распараллеливания запросов, PostgreSQL использует несколько фоновых рабочих процессов, а также обслуживающий процесс (backend), который в основном обрабатывает все запросы, отправляемые подключенным клиентом. Обслуживающий процесс состоит из 5 подсистем:

  1. Парсер (parser) преобразовывает текст на языке SQL в дерево разбора;
  2. Анализатор запроса (analyzer)  генерирует из дерева разбора начальный логический план запроса (реляционное выражение);
  3. Система правил (rewriter) принимает разобранный запрос, одно дерево запроса, а также  определённые пользователем правила перезаписи, представленные деревьями с некоторой дополнительной информацией, и создаёт определенное количество деревьев запросов;
  4. Планировщик (planner) создает наиболее оптимальный план выполнения  запроса на основе множества факторов;
  5. Исполнитель (executor) выполняет запрос, обращаясь к таблицам и индексам в том порядке, который был создан деревом плана, и формирует результирующий набор строк, возвращаемый клиенту в виде серии сообщений.

 

В данном разделе представлен краткий обзор этих подсистем. Поскольку планировщик и исполнитель достаточно сложны, их подробное объяснение дано в последующих разделах. 

Примечание: подробное описание выполнения запросов в PostgreSQL Вы сможете найти в  официальном документе.

 

Парсер

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

Рассмотрим следующий запрос:

testdb=# SELECT id, data FROM tbl_a WHERE id < 300 ORDER BY data;

 

Дерево разбора - это дерево, корневым узлом которого является структура SelectStmt.

SelectStmt:
typedef struct SelectStmt
{
        NodeTag         type;
 
        /*
         * These fields are used only in "leaf" SelectStmts.
         */
        List       *distinctClause;     /* NULL, list of DISTINCT ON exprs, or
                                         * lcons(NIL,NIL) for all (SELECT DISTINCT) */
        IntoClause *intoClause;         /* target for SELECT INTO */
        List       *targetList;         /* the target list (of ResTarget) */
        List       *fromClause;         /* the FROM clause */
        Node       *whereClause;        /* WHERE qualification */
        List       *groupClause;        /* GROUP BY clauses */
        Node       *havingClause;       /* HAVING conditional-expression */
        List       *windowClause;       /* WINDOW window_name AS (...), ... */
 
        /*
         * In a "leaf" node representing a VALUES list, the above fields are all
         * null, and instead this field is set.  Note that the elements of the
         * sublists are just expressions, without ResTarget decoration. Also note
         * that a list element can be DEFAULT (represented as a SetToDefault
         * node), regardless of the context of the VALUES list. It's up to parse
         * analysis to reject that where not valid.
         */
        List       *valuesLists;        /* untransformed list of expression lists */
 
        /*
         * These fields are used in both "leaf" SelectStmts and upper-level
         * SelectStmts.
         */
        List       *sortClause;         /* sort clause (a list of SortBy's) */
        Node       *limitOffset;        /* # of result tuples to skip */
        Node       *limitCount;         /* # of result tuples to return */
        List       *lockingClause;      /* FOR UPDATE (list of LockingClause's) */
        WithClause *withClause;         /* WITH clause */
 
        /*
         * These fields are used only in upper-level SelectStmts.
         */
        SetOperation op;                /* type of set op */
        bool            all;            /* ALL specified? */
        struct SelectStmt *larg;        /* left child */
        struct SelectStmt *rarg;        /* right child */
        /* Eventually add fields for CORRESPONDING spec here */
} SelectStmt;

 

 

При генерации дерева разбора парсер проверяет только синтаксис входного запроса. Поэтому он возвращает ошибку только в том случае, если в запросе есть синтаксическая ошибка.

Семантику входного запроса парсер не проверяет. Например, даже если запрос содержит несуществующее имя таблицы, парсер не сможет выдать соответствующую ошибку. Семантическими проверками занимаются анализаторы.

 

Анализатор

Анализатор выполняет семантический анализ дерева разбора, сгенерированного парсером, и генерирует дерево запросов.

Корнем дерева запросов является структура Query,  содержащая метаданные соответствующего запроса, такие как тип команды (SELECT, INSERT или другие), а также несколько листьев. Каждый лист образует список или дерево и содержит данные для каждого пункта.

Query:
/*
 * Query -
 *                   Parse analysis turns all statements into a Query tree
 *                   for further processing by the rewriter and planner.
 *
 *                   Utility statements (i.e. non-optimizable statements) have the
 *                   utilityStmt field set, and the Query itself is mostly dummy.
 *                   DECLARE CURSOR is a special case: it is represented like a SELECT,
 *                   but the original DeclareCursorStmt is stored in utilityStmt.
 *
 *                   Planning converts a Query tree into a Plan tree headed by a PlannedStmt
 *                   node --- the Query structure is not used by the executor.
 */
typedef struct Query
{
                    NodeTag                        type;
 
                    CmdType                      commandType;            /* select|insert|update|delete|merge|utility */
 
                    /* where did I come from? */
                    QuerySource querySource pg_node_attr(query_jumble_ignore);
 
                    /*
                    * query identifier (can be set by plugins); ignored for equal, as it
                    * might not be set; also not stored.  This is the result of the query
                    * jumble, hence ignored.
                    */
                    uint64                             queryId pg_node_attr(equal_ignore, query_jumble_ignore, read_write_ignore, read_as(0));
 
                    /* do I set the command result tag? */
                    bool                                 canSetTag pg_node_attr(query_jumble_ignore);
 
                    Node              *utilityStmt;               /* non-null if commandType == CMD_UTILITY */
 
                    /*
                    * rtable index of target relation for INSERT/UPDATE/DELETE/MERGE; 0 for
                    * SELECT.  This is ignored in the query jumble as unrelated to the
                    * compilation of the query ID.
                    */
                    int                                                        resultRelation pg_node_attr(query_jumble_ignore);
 
                    /* has aggregates in tlist or havingQual */
                    bool                                 hasAggs pg_node_attr(query_jumble_ignore);
                    /* has window functions in tlist */
                    bool                                 hasWindowFuncs pg_node_attr(query_jumble_ignore);
                    /* has set-returning functions in tlist */
                    bool                                 hasTargetSRFs pg_node_attr(query_jumble_ignore);
                    /* has subquery SubLink */
                    bool                                 hasSubLinks pg_node_attr(query_jumble_ignore);
                    /* distinctClause is from DISTINCT ON */
                    bool                                 hasDistinctOn pg_node_attr(query_jumble_ignore);
                    /* WITH RECURSIVE was specified */
                    bool                                 hasRecursive pg_node_attr(query_jumble_ignore);
                    /* has INSERT/UPDATE/DELETE in WITH */
                    bool                                 hasModifyingCTE pg_node_attr(query_jumble_ignore);
                    /* FOR [KEY] UPDATE/SHARE was specified */
                    bool                                 hasForUpdate pg_node_attr(query_jumble_ignore);
                    /* rewriter has applied some RLS policy */
                    bool                                 hasRowSecurity pg_node_attr(query_jumble_ignore);
                    /* is a RETURN statement */
                    bool                                 isReturn pg_node_attr(query_jumble_ignore);
 
                    List                 *cteList;                      /* WITH list (of CommonTableExpr's) */
 
                    List                 *rtable;                                            /* list of range table entries */
 
                    /*
                    * list of RTEPermissionInfo nodes for the rtable entries having
                    * perminfoindex > 0
                    */
                    List                 *rteperminfos pg_node_attr(query_jumble_ignore);
                    FromExpr   *jointree;                      /* table join tree (FROM and WHERE clauses);
                                                                                                                                                                   * also USING clause for MERGE */
 
                    List                 *mergeActionList;    /* list of actions for MERGE (only) */
                    /* whether to use outer join */
                    bool                                 mergeUseOuterJoin pg_node_attr(query_jumble_ignore);
 
                    List                 *targetList;                                     /* target list (of TargetEntry) */
 
                    /* OVERRIDING clause */
                    OverridingKind override pg_node_attr(query_jumble_ignore);
 
                    OnConflictExpr *onConflict; /* ON CONFLICT DO [NOTHING | UPDATE] */
 
                    List                 *returningList;           /* return-values list (of TargetEntry) */
 
                    List                 *groupClause;           /* a list of SortGroupClause's */
                    bool                                 groupDistinct;               /* is the group by clause distinct? */
 
                    List                 *groupingSets;           /* a list of GroupingSet's if present */
 
                    Node              *havingQual;                                 /* qualifications applied to groups */
 
                    List                 *windowClause;       /* a list of WindowClause's */
 
                    List                 *distinctClause; /* a list of SortGroupClause's */
 
                    List                 *sortClause;                                   /* a list of SortGroupClause's */
 
                    Node              *limitOffset;              /* # of result tuples to skip (int8 expr) */
                    Node              *limitCount;                                   /* # of result tuples to return (int8 expr) */
                    LimitOption limitOption;                /* limit type */
 
                    List                 *rowMarks;                                    /* a list of RowMarkClause's */
 
                    Node              *setOperations;         /* set-operation tree if this is top level of
                                                                                                                                                                   * a UNION/INTERSECT/EXCEPT query */
 
                    /*
                    * A list of pg_constraint OIDs that the query depends on to be
                    * semantically valid
                    */
                    List                 *constraintDeps pg_node_attr(query_jumble_ignore);
 
                    /* a list of WithCheckOption's (added during rewrite) */
                    List                 *withCheckOptions pg_node_attr(query_jumble_ignore);
 
                    /*
                    * The following two fields identify the portion of the source text string
                    * containing this query.  They are typically only populated in top-level
                    * Queries, not in sub-queries.  When not set, they might both be zero, or
                    * both be -1 meaning "unknown".
                    */
                    /* start location, or -1 if unknown */
                    int                                                        stmt_location;
                    /* length in bytes; 0 means "rest of string" */
                    int                                                        stmt_len pg_node_attr(query_jumble_ignore);
} Query;

 

Дерево запросов, приведенное выше, можно описать следующим образом:

  • Targetlist - это список столбцов, которые являются результатом данного запроса. В данном примере список состоит из двух столбцов: 'id' и 'data'. Если во входном дереве запроса используется символ '∗∗', то анализатор заменит его на все столбцы;
  • Range – это список отношений, которые используются в запросе. В данном примере список содержит информацию о таблице 'tbl_a', такую как OID таблицы и ее имя;
  • Join tree хранит предложение FROM и предложения WHERE;
  • Sort clause представляет собой список SortGroupClause.

 

Подробное описание дерева запросов дано в  официальном документе.

 

Система правил

При необходимости система правил преобразует дерево запросов в соответствии с правилами, хранящимися в каталоге pg_rules . Система правил - достаточно интересная система, но мы даем лишь ее краткое описание, иначе данный раздел получился бы слишком большим.

Представление (VIEW)

Представления в PostgreSQL реализованы на основе системы правил. В случае, если представление задано командой CREATE VIEW, автоматически генерируется соответствующее правило, сохраняемое в каталоге.

Предположим, что представление, описанное ниже, уже задано,  а соответствующее правило хранится в системном каталоге pg_rules:

sampledb=# CREATE VIEW employees_list
sampledb-#      AS SELECT e.id, e.name, d.name AS department
sampledb-#            FROM employees AS e, departments AS d WHERE e.department_id = d.id;

 

Когда выдается запрос, содержащий представление, показанное ниже, синтаксический анализатор создает дерево разбора, как показано на рис. 12.

sampledb=# SELECT * FROM employees_list;

 

На данном этапе система правил обрабатывает узел таблицы диапазонов до дерева разбора подзапроса, который является соответствующим представлением, хранящимся в pg_rules.

 

Поскольку PostgreSQL реализует представления с помощью такого механизма, обновлять представления  было не возможно вплоть до выхода версии 9.2. Версии 9.3 сделала обновление представлений возможным; однако существует множество ограничений. Подробную информацию Вы найдете в  официальном документе.

 

Планировщик и Исполнитель

Задача планировщика —  построить наилучший план выполнения. Определённый SQL-запрос (а значит, и дерево запроса) на самом деле можно выполнить самыми разными способами, при этом получая одни и те же результаты. Если это не требует больших вычислений, оптимизатор запросов будет перебирать все возможные варианты планов, чтобы в итоге выбрать тот, который должен выполниться быстрее остальных.

Планировщик в PostgreSQL основан на оптимизации на основе затрат. Он не поддерживает оптимизацию на основе правил или подсказок. Планировщик является самой сложной подсистемой в PostgreSQL, поэтому его обзор будет предоставлен отдельно.

 

Примечание: pg_hint_plan

pg_hint_plan — модуль, позволяющий управлять планом выполнения с указаниями, записываемыми в комментариях особого вида. Модуль pg_hint_plan позволяет корректировать планы выполнения, применяя так называемые «указания», записываемые в виде простых описаний в SQL-комментариях особого вида. Дополнительная информация предоставлена на  официальном сайте.

Выполняя любой полученный запрос, PostgreSQL разрабатывает для него план запроса. Выбор правильного плана, соответствующего структуре запроса и характеристикам данным, крайне важен для хорошей производительности, поэтому в системе работает сложный планировщик, задача которого — подобрать хороший план. Узнать, какой план был выбран для какого-либо запроса, можно с помощью команды EXPLAIN. Пример показан ниже:

testdb=# EXPLAIN SELECT * FROM tbl_a WHERE id < 300 ORDER BY data;
                          QUERY PLAN
---------------------------------------------------------------
 Sort  (cost=182.34..183.09 rows=300 width=8)
   Sort Key: data
   ->  Seq Scan on tbl_a  (cost=0.00..170.00 rows=300 width=8)
         Filter: (id < 300)
(4 rows)

 

В результате получается дерево планов, показанное на рис. 13.

Дерево плана состоит из элементов, называемых узлами плана, и связано со списком plantree структуры PlannedStmt. Данные элементы определены в plannodes.h. Более подробная информация предоставлена в главе 3.3.3 и 3.5.4.2.

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

Например, дерево плана, показанное на рис. 13, представляет собой список из узла сортировки и узла последовательного сканирования. Поэтому исполнитель сканирует таблицу tbl_a последовательным сканированием, а затем сортирует полученный результат.

Исполнитель читает и записывает таблицы и индексы в кластере баз данных с помощью менеджера буферов, описанного в Разделе 8. При обработке запроса исполнитель использует некоторые области памяти, такие как temp_buffers и work_mem, выделенные заранее, и при необходимости создает временные файлы.

Кроме того, при обращении к кортежам PostgreSQL использует механизм управления параллелизмом для поддержания согласованности и изоляции выполняемых транзакций. Механизм управления параллелизмом описан в главе 5.

 

 

Узнать стоимость решенияЗапросить видео презентацию

← Предыдущая статья
Архитектура памяти PostgreSQL
Следующая статья →
Оценка стоимости при работе с однотабличным запросом PostgreSQL

Решения

Анализировать ФинансыУвеличивайте ПродажиОптимальный Склад и ЛогистикаМаркетинговые Метрики

Клиенты
  • Торгово-производственному холдингу ТБМ, специализирующемуся на поставке комплектующих и фурнитуры для производства окон, дверей, стеклопакетов и мебели, был необходим аналитический инструмент для выявления узким мест и поиска зон роста бизнеса и, как результат, оптимизации процессов. Добиться этого можно было, только внедрив data-driven подход.

  • ООО "Интернэшнл Ресторант Брэндс" – это крупнейший франчайзинговый партнер компании Yum! Brands Russia & CIS в России, отвечающий за рост и развитие бренда KFC на территории РФ. На сегодняшний день у компании более 350 ресторанов. Ежедневно в рестораны приходит 200 000+ гостей.

  • ПАО «Транснефть» – крупнейшая российская нефтепроводная компания. «Транснефть» обеспечивает транспортировку более 85% добываемых в России нефти и нефтепродуктов.

  • ГК «Агропромкомплектация-Курск» - одна из ведущих в Российской Федерации агропромышленных компаний с полным производственным циклом "от поля до прилавка". За 32 года работы на рынке компания заслуженно завоевала репутацию одного из лидеров страны в производстве свинины и молока.

  • Решения
    • Дистрибуция
    • Розничная торговля
    • Производство
    • Операторы связи
    • Страхование
    • Банки
    • Лизинг
    • Логистика
    • Нефтегазовый сектор
    • Медицина
    • Сеть ресторанов
    • E-Commerce
    • Энергетика
    • Фармацевтика
  • Услуги
    • Переход на отечественные BI и DWH
    • Консалтинг
    • Пилотный проект
    • Обучение и сертификация
    • Бесплатное обучение
    • Техническая поддержка
    • Технические задания
    • Сбор требований для проекта внедрения BI-системы
    • CI/CD для DWH
    • Аудит BI приложений
    • Выделенная команда
    • Настойка и поддержка баз данных
    • Разработка BI Стратегии
    • Styleguide для BI-системы
    • Как выбрать BI-систему
  • Платформы
    • FineBI
    • FineReport
    • FineDataLink
    • Коннекторы данных из 1С в BI
    • Airflow + NiFi
    • Visiology
    • Luxms BI
    • Modus BI
    • PIX BI
    • Arenadata
    • ClickHouse
    • Greenplum
    • Postgres Professional
    • Open-source BI: Superset/Metabase
    • Loginom
    • Yandex.DataLens
    • AI / Исскуственный интеллект
    • Optimacros
    • Шины данных
  • Курсы
    • Учебный курс Информационная грамотность
    • Учебный курс для бизнес-аналитиков
    • Учебный курс для системных аналитиков
    • Учебный курс по Data Governance
    • Учебный курс Как стать CDO
    • Учебный курс Современная архитектура хранилища данных
    • Учебный курс по Fine BI
    • Учебный курс по FineReport
    • Учебный курс по DWH
    • Учебный курс по Data Science (ML, AI)
    • Учебный курс по PostgreSQL
    • Учебный курс по Apache Airflow и NiFi
    • Учебный курс по Open-source BI
    • Учебный курс по ClickHouse
    • Учебный курс по DataLens
    • Учебный курс по Loginom
    • Учебный курс по Modus BI и ETL
    • Учебный курс по Visiology
    • Учебный курс по dbt
  • Функциональные решения
    • Создание Data Lake
    • Цифровая трансформация
    • Управление по KPI
    • Финансы
    • Продажи
    • Склад
    • HR
    • Маркетинг
    • Внутренний аудит
    • Категорийный менеджмент
    • S&OP и прогнозная аналитика
    • Геоаналитика
    • Цепочки поставок (SCM)
    • AutoML
    • Process Mining
    • Сквозная аналитика
  • Компания
    • О нас
    • Руководство
    • Новости
    • Клиенты
    • Скачать
    • Контакты
    • Политика конфиденциальности
RutubeVkontakteLinkedInYouTube
ООО "Би Ай Консалт",
ИНН: 7811437757,
ОГРН: 1097847154184
199178, Россия,
Санкт-Петербург,
6-ая линия В.О., Д. 63, 4 этаж
Тел: +7 (812) 334-08-01
Тел: +7 (499) 608-13-06
E-mail: info@biconsult.ru

 

 

 

 

 

×

Пользуясь сайтом, вы соглашаетесь с использованием cookies и политикой конфиденциальности.