×
Мы обрабатываем cookies, чтобы сделать наш сайт удобнее и персонализированнее для вас. Подробнее: политика использования «cookies» и «политики конфиденциальности».

Для самостоятельной настройки ознакомьтесь с инструкцией

Дополнительные настройки cookies в браузерах

Файлы cookie автоматически загружаются в ваш браузер при посещении веб-сайта. У вас есть возможность управлять этими файлами. Если Вы не согласны с использованием файлов cookies, запретите их сохранение на своём устройстве, удалите уже имеющиеся файлы cookies через настройки браузера или прекратите использование сайта.

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

Инструкция по отключению cookies
Принять
Настроить
Отклонить

ДОКУМЕНТАЦИЯ

Выберите версию, форк и язык для СУБД Digital Q.DataBase, чтобы прочитать или скачать всю документацию.
Техподдержка
Документация
Диасофт
Авторские права © 2016–2025 ООО "Диасофт Экосистема"
Скачать всю документацию:

4.1.5. Конвейерный режим

4.1.5.1. Использование режима конвейеризации
4.1.5.2. Функции, связанные с режимом конвейерной обработки
4.1.5.3. Применение конвейерного режима

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

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

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

Несмотря на то, что libpqинтерфейс программирования приложений (API) конвейерной обработки был представлен в Digital Q.DataBase версии 14, это клиентская функциональность, которая не требует специальной поддержки со стороны сервера и работает с любым сервером, поддерживающим расширенный протокол запросов версии 3. Для получения дополнительной информации см. Раздел 7.4.2.4.

4.1.5.1. Использование режима конвейеризации #

Для использования конвейеров приложение должно переключить соединение в режим конвейеризации, что выполняется с помощью функции PQenterPipelineMode. PQpipelineStatus может использоваться для проверки того, активен ли режим конвейеризации. В режиме конвейеризации разрешены только асинхронные операции , использующие расширенный протокол запросов, разрешены, тогда как командные строки, содержащие несколько SQL-команд, не допускаются, равно как и COPY. Использование функций синхронного выполнения команд, таких как PQfn, PQexec, PQexecParams, PQprepare, PQexecPrepared, PQdescribePrepared, PQdescribePortal, PQclosePrepared, PQclosePortal, является состоянием ошибки. PQsendQuery также запрещена, поскольку в ней используется протокол простых запросов. После обработки результатов всех отправленных команд и получения завершающего результата конвейера приложение может вернуться в режим без конвейеризации с помощью PQexitPipelineMode.

Примечание

Режим конвейеризации лучше всего использовать в libpq в неблокирующем режиме. При использовании в блокирующем режиме возможно возникновение взаимной блокировки между клиентом и сервером. [15]

4.1.5.1.1. Выполнение запросов #

После перехода в режим конвейеризации приложение отправляет запросы с помощью функции PQsendQueryParams или её аналога для подготовленных запросов PQsendQueryPrepared. Данные запросы помещаются в очередь на стороне клиента до их отправки на сервер; это происходит в тех случаях, когда PQpipelineSync используется для создания точки синхронизации в конвейере, или когда PQflush вызывается. Функции PQsendPrepare, PQsendDescribePrepared, PQsendDescribePortal, PQsendClosePreparedи PQsendClosePortal также поддерживают работу в конвейерном режиме. Порядок обработки результатов описан ниже.

Сервер выполняет операторы и возвращает результаты в том же порядке, в котором их отправляет клиент. Сервер начинает выполнение команд в конвейере немедленно, не ожидая его завершения. Следует учитывать, что на стороне сервера результаты буферизуются; сервер очищает данный буфер при установке точки синхронизации с помощью функции PQpipelineSync или PQsendPipelineSync, а также при вызове функции PQsendFlushRequest вызывается. Если при выполнении какого-либо оператора возникает ошибка, сервер прерывает текущую транзакцию и не выполняет последующие команды в очереди до достижения следующей точки синхронизации; PGRES_PIPELINE_ABORTED для каждой такой команды формируется результат. (Это правило остается в силе, даже если команды в конвейере вызовут откат транзакции.) Обработка запросов возобновляется после точки синхронизации.

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

4.1.5.1.2. Обработка результатов #

Чтобы обработать результат одного запроса в конвейере, приложение многократно вызывает функцию PQgetResult и обрабатывает каждый результат до тех пор, пока PQgetResult не вернет значение NULL. Затем результат следующего запроса в конвейере может быть получен путем повторного вызова функции PQgetResult после чего цикл повторяется. Результаты отдельных операторов приложение обрабатывает в обычном режиме. Когда результаты всех запросов в конвейере будут возвращены, PQgetResult возвращает результат, содержащий значение статуса PGRES_PIPELINE_SYNC

Клиент может выбрать вариант с отложенной обработкой результатов до завершения отправки всего конвейера или совмещать её с отправкой последующих запросов; см. Раздел 4.1.5.1.4.

PQgetResult работает так же, как и при обычной асинхронной обработке, за исключением возможности появления новых PGresult типов PGRES_PIPELINE_SYNC и PGRES_PIPELINE_ABORTED. PGRES_PIPELINE_SYNC сообщается ровно один раз для каждого PQpipelineSync или PQsendPipelineSync в соответствующей точке конвейера. PGRES_PIPELINE_ABORTED выдается вместо обычного результата запроса при возникновении первой ошибки и для всех последующих результатов до следующего PGRES_PIPELINE_SYNC; см. Раздел 4.1.5.1.3.

PQisBusy, PQconsumeInput, и т. д. работают в штатном режиме при обработке результатов конвейера. В частности, вызов функции PQisBusy в середине конвейера возвращает 0, если результаты всех отправленных на данный момент запросов уже были получены.

libpq не предоставляет приложению никакой информации о текущем обрабатываемом запросе (за исключением того, что PQgetResult возвращает значение NULL, указывая на начало возврата результатов следующего запроса). Приложение должно самостоятельно отслеживать порядок отправки запросов для их сопоставления с соответствующими результатами. Как правило, для этой цели в приложениях используется конечный автомат или очередь FIFO.

4.1.5.1.3. Обработка ошибок #

С точки зрения клиента, после того как PQresultStatus возвращает значение PGRES_FATAL_ERROR, конвейер помечается как прерванный. PQresultStatus будет возвращать PGRES_PIPELINE_ABORTED результат для каждой оставшейся в очереди операции в прерванном конвейере. Результат для PQpipelineSync или PQsendPipelineSync возвращается как PGRES_PIPELINE_SYNC для сигнализации о завершении прерванного конвейера и возобновлении обычной обработки результатов.

Клиент должен обрабатывает результаты с помощью функции PQgetResult в процессе восстановления после ошибки.

Если в конвейере использовалась неявная транзакция, то уже выполненные операции откатываются, а операции, находившиеся в очереди после сбойной операции, полностью пропускаются. Аналогичное поведение сохраняется, если в конвейере запускается и фиксируется одна явная транзакция (т. е. первым оператором является BEGIN а последним — COMMIT), за исключением того, что по завершении работы конвейера сеанс остается в состоянии прерванной транзакции. Если конвейер содержит несколько явных транзакций, то все транзакции, зафиксированные до возникновения ошибки, остаются зафиксированными, текущая выполняемая транзакция прерывается, а все последующие операции, включая последующие транзакции, полностью пропускаются. Если точка синхронизации конвейера возникает в момент, когда явный блок транзакции находится в состоянии прерывания, выполнение следующего конвейера будет немедленно прекращено, если только следующая команда не переведет транзакцию в нормальный режим с помощью ROLLBACK.

Примечание

Клиент не должен предполагать, что работа зафиксирована, когда он отправляет её COMMIT — фиксация считается завершенной только при получении соответствующего результата. Поскольку ошибки поступают асинхронно, приложению необходимо иметь возможность возобновления работы с последнего полученного зафиксированное изменение и повторную отправку результатов выполненной после этого момента работы в случае возникновения ошибки.

4.1.5.1.4. Чередование обработки результатов и отправки запросов #

Во избежание взаимоблокировок в больших конвейерах архитектуру клиента следует основывать на неблокирующем цикле событий с использованием таких средств операционной системы, как select, poll, WaitForMultipleObjectEx, и т. д.

Как правило, клиентскому приложению следует поддерживать очередь задач, ожидающих отправки, и очередь задач, которые уже были отправлены, но результаты выполнения которых еще не обработаны. Когда сокет становится доступен для записи, следует передать на выполнение дополнительный объем задач. Когда сокет становится доступен для чтения, следует прочитать результаты и обработать их, сопоставляя их со следующей записью в соответствующей очереди результатов. Исходя из объема доступной памяти, результаты из сокета следует считывать часто: для чтения результатов нет необходимости ждать завершения работы конвейера. Область действия конвейеров должна ограничиваться логическими единицами работы, как правило (но не обязательно), одной транзакцией на конвейер. Нет необходимости выходить из режима конвейера и повторно входить в него между конвейерами или ожидать завершения одного конвейера перед отправкой следующего.

Пример использования select() и простого конечного автомата для отслеживания отправленных и полученных задач приведен в файле src/test/modules/libpq_pipeline/libpq_pipeline.c в составе дистрибутива исходных кодов PostgreSQL.

4.1.5.2. Функции, связанные с режимом конвейерной обработки #

PQpipelineStatus #

Возвращает текущий статус режима конвейера для libpq соединения.

PGpipelineStatus PQpipelineStatus(const PGconn *conn);

PQpipelineStatus функция может возвращать одно из следующих значений:

PQ_PIPELINE_ON

Параметр libpq соединение находится в режиме конвейерной обработки.

PQ_PIPELINE_OFF

Параметр libpq соединение находится пытаться в режиме конвейерной обработки.

PQ_PIPELINE_ABORTED

Параметр libpq соединение находится в конвейерном режиме, и при обработке текущего конвейера произошла ошибка. Флаг прерывания сбрасывается, когда PQgetResult возвращает результат типа PGRES_PIPELINE_SYNC.

PQenterPipelineMode #

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

int PQenterPipelineMode(PGconn *conn);

В случае успеха возвращает 1. Возвращает 0 и не выполняет никаких действий, если в данный момент соединение не является свободным, то есть для него готов результат или оно ожидает получения дополнительных данных от сервера и т. д. Фактически данная функция ничего не отправляет на сервер, она лишь изменяет libpq соединение состояние.

PQexitPipelineMode #

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

int PQexitPipelineMode(тип PGconn *объект conn);

В случае успешного выполнения функция возвращает 1. Если соединение не находится в конвейерном режиме, функция не выполняет никаких действий и возвращает 1. Если обработка текущего оператора не завершена или если соответствующая функция или PQgetResult не была вызвана для получения результатов всех ранее отправленных запросов, возвращается 0 (в этом случае для используйте функцию PQerrorMessage получения дополнительных сведений о возникшем сбое).

PQpipelineSync #

Отмечает точку синхронизации в конвейере путем отправки сообщения синхронизации и принудительной очистки буфера передачи. Это служит разделителем неявной транзакции и механизмом восстановления после ошибки point; see Раздел 4.1.5.1.3.

int PQpipelineSync(PGconn *conn);

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

PQsendPipelineSync #

Отмечает точку синхронизации в конвейере путем отправки сообщения синхронизации без очистки буфера отправки. Это служит разделителем неявной транзакции и механизмом восстановления после ошибки point; see Раздел 4.1.5.1.3.

int PQsendPipelineSync(PGconn *conn);

В случае успешного выполнения функция возвращает 1. Функция возвращает 0, если соединение не находится в режиме конвейеризации или если отправка сообщения синхронизации завершилась неудачно. Следует учитывать, что само сообщение не сбрасывается на сервер автоматически; используйте функцию PQflush если это необходимо.

PQsendFlushRequest #

Отправляет серверу запрос на очистку его выходного буфера.

int PQsendFlushRequest(PGconn *conn);

В случае успешного выполнения функция возвращает 1. Функция возвращает 0 при возникновении любой ошибки.

Сервер автоматически очищает свой выходной буфер в результате PQpipelineSync вызова или при любом запросе вне режима конвейеризации; данная функция полезна для принудительной очистки сервером своего выходного буфера в режиме конвейеризации без установления точки синхронизации. Обратите внимание, что автоматически запрос на сервер не отправляется; используйте функцию PQflush если это необходимо.

4.1.5.3. Применение конвейерного режима #

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

Конвейерный режим наиболее эффективен в тех случаях, когда сервер удален, то есть когда сетевая задержка («время круговой задержки») велика, а также при быстром последовательном выполнении множества мелких операций. Использование конвейерных команд обычно менее выгодно, если время выполнения каждого запроса многократно превышает время приема-передачи данных между клиентом и сервером. Выполнение операции из 100 операторов на сервере с временем приема-передачи 300 мс без конвейеризации заняло бы 30 секунд только за счет сетевых задержек; при использовании конвейеризации время ожидания результатов от сервера может сократиться до 0,3 с.

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

Режим конвейерной обработки малоэффективен, если для формирования следующей операции приложению требуются сведения, полученные в результате выполнения предыдущей операции. В подобных ситуациях на стороне клиента необходимо вводить точку синхронизации и ожидать завершения полного цикла приема-передачи данных (round-trip) между клиентом и сервером для получения требуемых результатов. Однако структуру клиентского приложения зачастую можно изменить таким образом, чтобы обмен необходимой информацией происходил на стороне сервера. Особенно подходящими кандидатами для такой оптимизации являются циклы «чтение-изменение-запись» (read-modify-write); например:

BEGIN;
SELECT x FROM mytable WHERE id = 42 FOR UPDATE;
-- результат: x=2
-- клиент прибавляет 1 к x:
UPDATE mytable SET x = 3 WHERE id = 42;
COMMIT;

можно выполнить гораздо эффективнее с помощью выражения:

UPDATE mytable SET x = x + 1 WHERE id = 42;

Конвейерная обработка менее полезна и более сложна в тех случаях, когда один конвейер содержит несколько транзакций (см. Раздел 4.1.5.1.3).



[15] Клиент будет заблокирован при попытке отправить запросы серверу, в то время как сервер будет заблокирован при попытке отправить клиенту результаты запросов, которые им уже были обработаны. Это происходит только в том случае, если клиент отправляет количество запросов, достаточное для заполнения как своего выходного буфера, так и приемного буфера сервера до перехода к обработке входящих данных от сервера, однако точно предсказать момент наступления этого события сложно.

Наверх
свяжитесь
с нами
контакты
Для прямой связи с нами вы можете использовать контакты ниже, либо оставить заявку через форму обратной связи, и мы обязательно свяжемся с вами

*поля обязательные к заполнению