# Этапы выполнения запроса

Установим параметры, которые покажут примерное время выполнения этапов обработки:

    => ALTER SYSTEM SET log_parser_stats = on;

    ALTER SYSTEM

    => ALTER SYSTEM SET log_planner_stats = on;

    ALTER SYSTEM

    => ALTER SYSTEM SET log_executor_stats = on;

    ALTER SYSTEM

    => SELECT pg_reload_conf();

     pg_reload_conf
    ----------------
     t
    (1 row)

Обычный удобный способ узнать время выполнения и время планирования (включая разбор и переписывание) - команда EXPLAIN ANALYZE. Ее основное назначение - показать план выполнения запроса, но о плане как таковом мы будем говорить позже. Пока обратите внимание на две последние строки:

    => EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
    SELECT * FROM ticket_flights;

                            QUERY PLAN
    ----------------------------------------------------------
     Seq Scan on ticket_flights (actual rows=8391852 loops=1)
     Planning time: 4.235 ms
     Execution time: 1993.501 ms
    (3 rows)

Благодаря установленным нами параметрам, из журнала сообщений можно получить более подробную информацию, хотя обычно это и не требуется. Выведем только основные цифры (elapsed):

    postgres$ tail -n 50 /var/log/postgresql/postgresql-10-main.log | egrep 'LOG: |elapsed'

    2019-02-13 13:02:46.387 MSK [3054] postgres@demo LOG:  PARSER STATISTICS
    	!	0.000000 s user, 0.000000 s system, 0.000029 s elapsed
    2019-02-13 13:02:46.392 MSK [3054] postgres@demo LOG:  PARSE ANALYSIS STATISTICS
    	!	0.000000 s user, 0.000000 s system, 0.005306 s elapsed
    2019-02-13 13:02:46.392 MSK [3054] postgres@demo LOG:  REWRITER STATISTICS
    	!	0.000000 s user, 0.000000 s system, 0.000001 s elapsed
    2019-02-13 13:02:46.397 MSK [3054] postgres@demo LOG:  PLANNER STATISTICS
    	!	0.000000 s user, 0.004000 s system, 0.004176 s elapsed
    2019-02-13 13:02:48.391 MSK [3054] postgres@demo LOG:  EXECUTOR STATISTICS
    	!	0.536000 s user, 0.616000 s system, 1.997833 s elapsed

Разные способы измерения выдают несколько отличающиеся результаты.

# Простой запрос

Протокол простых запросов применяется, когда на сервер просто отправляется оператор (и, если это SELECT или команда с фразой RETURNING, то мы ожидаем получение всех строк результата). Например:

    => SELECT model FROM aircrafts WHERE aircraft_code = '773';

         model
    ---------------
     Боинг 777-300
    (1 row)

# Подготовленные операторы

Создадим подготовленный оператор для нашего запроса:

    => PREPARE model(varchar) AS
      SELECT model FROM aircrafts WHERE aircraft_code = $1;

    PREPARE

Теперь мы можем вызывать оператор по имени:

    => EXECUTE model('773');

         model
    ---------------
     Боинг 777-300
    (1 row)

    => EXECUTE model('763');

         model
    ---------------
     Боинг 767-300
    (1 row)

Все подготовленные операторы можно увидеть в представлении:

    => SELECT * FROM pg_prepared_statements \gx

    -[ RECORD 1 ]---+--------------------------------------------------------
    name            | model
    statement       | PREPARE model(varchar) AS                              +
                    |   SELECT model FROM aircrafts WHERE aircraft_code = $1;
    prepare_time    | 2019-02-13 13:02:48.603462+03
    parameter_types | {"character varying"}
    from_sql        | t

Если подготовленный оператор больше не нужен, его можно удалить командой DEALLOCATE, но в любом случае оператор пропадет при завершении сеанса.

    => \c

    You are now connected to database "demo" as user "postgres".

    => SELECT * FROM pg_prepared_statements;

     name | statement | prepare_time | parameter_types | from_sql
    ------+-----------+--------------+-----------------+----------
    (0 rows)

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

# Курсоры

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

На SQL использование курсоров можно продемонстрировать следующим образом. Объявляем (и сразу же открываем) курсор и выбираем первую строку:

    => BEGIN;

    BEGIN

    => DECLARE c CURSOR FOR SELECT * FROM aircrafts;

    DECLARE CURSOR

    => FETCH c;

     aircraft_code |     model     | range
    ---------------+---------------+-------
     773           | Боинг 777-300 | 11100
    (1 row)

Читаем вторую строку результата и закрываем открытый курсор.

    => FETCH c;

     aircraft_code |     model     | range
    ---------------+---------------+-------
     763           | Боинг 767-300 |  7900
    (1 row)

    => CLOSE c;

    CLOSE CURSOR

    => COMMIT;

    COMMIT

Конец демонстрации.