Обновляемый вид с Postgresql и вычисляемыми полями - PullRequest
0 голосов
/ 07 мая 2020

У меня есть представление, которое вычисляет некоторые поля. Я хотел обновить данные из этого представления (привязка модели к веб-платформе). У меня были проблемы, потому что вычисляемые поля не являются настоящими столбцами. Затем я создал функцию триггера, которая обрабатывает это.

Я провел тест «обновление из события» и «обновление из просмотра событий». Похоже, что функция, запускаемая обновлением, работает намного медленнее, чем «нормальное» обновление событий. Вот результат теста для 1000 создания / обновления событий:

# This report shows the user CPU time, system CPU time, the sum of the user and system CPU times, and the elapsed real time. The unit of time is seconds.
>> CREATE
              user     system      total        real
EVENT     3.268527   0.248713   3.517240 (  5.777483)
VIEW      3.423386   0.232107   3.655493 (  5.977695)
>> UPDATE
              user     system      total        real
EVENT     2.491350   0.227937   2.719287 (  4.586648)
VIEW      2.861838   0.199566   3.061404 (  6.240148)
=> nil

CREATE TABLE инструкция:

CREATE TABLE public.events (
    id bigint NOT NULL,
    uuid uuid DEFAULT public.gen_random_uuid() NOT NULL,
    establishment_id bigint,
    name character varying NOT NULL,
    start_at timestamp without time zone NOT NULL,
    end_at timestamp without time zone NOT NULL,
    canceled boolean DEFAULT false NOT NULL,
    created_at timestamp(6) without time zone NOT NULL,
    updated_at timestamp(6) without time zone NOT NULL,
    published boolean DEFAULT false
);

EXPLAIN (ANALYZE, BUFFERS)

# EXPLAIN (ANALYZE, BUFFERS) UPDATE events SET name='some name', updated_at='2020-05-07 10:05:07.769711' WHERE events.id = 16212


Update on events  (cost=0.29..8.38 rows=1 width=156) (actual time=0.187..0.194 rows=0 loops=1)
  Buffers: shared hit=17 dirtied=2
  ->  Index Scan using events_pkey on events  (cost=0.29..8.38 rows=1 width=156) (actual time=0.081..0.100 rows=1 loops=1)
        Index Cond: (id = 16212)
        Buffers: shared hit=7 dirtied=2
Planning Time: 7.301 ms
Execution Time: 1.127 ms


# EXPLAIN (ANALYZE, BUFFERS) UPDATE invitations_event_view SET name='some name', updated_at='2020-05-07 10:05:07.769711' WHERE invitations_event_view.id = 16212


Update on invitations_event_view invitations_event_view_1  (cost=4.73..26.41 rows=1 width=1164) (actual time=1.800..1.810 rows=0 loops=1)
  Buffers: shared hit=15 dirtied=1
  ->  Subquery Scan on invitations_event_view  (cost=4.73..26.41 rows=1 width=1164) (actual time=0.418..0.455 rows=1 loops=1)
        Buffers: shared hit=4 dirtied=1
        ->  GroupAggregate  (cost=4.73..26.40 rows=1 width=369) (actual time=0.353..0.371 rows=1 loops=1)
              Group Key: e.id
              Buffers: shared hit=4 dirtied=1
              ->  Nested Loop Left Join  (cost=4.73..26.21 rows=1 width=157) (actual time=0.251..0.307 rows=1 loops=1)
                    Buffers: shared hit=4 dirtied=1
                    ->  Nested Loop Left Join  (cost=4.45..17.91 rows=1 width=161) (actual time=0.106..0.144 rows=1 loops=1)
                          Join Filter: (i.event_id = e.id)
                          Buffers: shared hit=4 dirtied=1
                          ->  Index Scan using events_pkey on events e  (cost=0.29..8.38 rows=1 width=141) (actual time=0.030..0.049 rows=1 loops=1)
                                Index Cond: (id = 16212)
                                Buffers: shared hit=3 dirtied=1
                          ->  Bitmap Heap Scan on invitations i  (cost=4.16..9.50 rows=2 width=28) (actual time=0.041..0.050 rows=0 loops=1)
                                Recheck Cond: (event_id = 16212)
                                Buffers: shared hit=1
                                ->  Bitmap Index Scan on index_invitations_on_event_id  (cost=0.00..4.16 rows=2 width=0) (actual time=0.021..0.030 rows=0 loops=1)
                                      Index Cond: (event_id = 16212)
                                      Buffers: shared hit=1
                    ->  Index Scan using guests_pkey on guests g  (cost=0.28..8.30 rows=1 width=12) (actual time=0.017..0.026 rows=0 loops=1)
                          Index Cond: (i.guest_id = id)
Planning Time: 3.420 ms
Trigger invitations_event_view_on_update_trigger: time=1.254 calls=1
Execution Time: 2.425 ms

Вот Вот функция:

CREATE OR REPLACE FUNCTION invitations_event_view_on_update() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
  UPDATE events
  SET establishment_id = NEW.establishment_id,
    name = NEW.name,
    start_at = NEW.start_at,
    end_at = NEW.end_at,
    canceled = NEW.canceled,
    updated_at = NEW.updated_at,
    published = NEW.published
  WHERE id = OLD.id;
  RETURN NEW;
END $$;

Вот создание триггера

CREATE TRIGGER invitations_event_view_on_update_trigger
        INSTEAD OF UPDATE ON invitations_event_view
        FOR EACH ROW EXECUTE FUNCTION invitations_event_view_on_update();

У меня вопрос, как я могу увеличить производительность этой функции?

Думаю, это потому, что я установил все поля, а не только обновления, но я не уверен на 100%. Если бы специалисты могли подсказать, было бы здорово.

EDIT

Попробуйте с prepare.

CREATE OR REPLACE FUNCTION invitations_event_view_on_update() RETURNS trigger LANGUAGE plpgsql AS $$
  BEGIN
    PREPARE event_update(bigint, bigint, character varying, timestamp without time zone, timestamp without time zone, integer, integer, boolean, timestamp without time zone, text, timestamp without time zone, boolean, integer) AS
      UPDATE events
      SET establishment_id = $2,
        name = $3,
        start_at = $4,
        end_at = $5,
        canceled = $6,
        updated_at = $7,
        published = $8
      WHERE id = $1;
    EXECUTE event_update(OLD.id, NEW.establishment_id, NEW.name, NEW.start_at, NEW.end_at, NEW.canceled, NEW.updated_at, NEW.published);
    DEALLOCATE PREPARE event_update;
    RETURN NEW;
  END
$$;
...