Запрос просмотра, который занимает слишком много времени - postgresql - PullRequest
0 голосов
/ 02 декабря 2018

У меня есть представление, которое запрашивает из 2 таблиц: таблица сообщений и таблица состояния сообщений.каждое сообщение имеет несколько статусов.

Цель представления состоит в том, чтобы рассчитать для каждого сообщения его первый и последний статусы:

with last_msg_status as (
  select distinct on (message_id) message_id,date,type
  from message_status
  order by message_id,date desc
), first_msg_status as (
  select distinct on (message_id) message_id,date,type
  from message_status
  order by message_id,date
)
select *
from messages m
  join last_msg_status ls on ls.message_id = m.id
  join first_msg_status fs on fs.message_id = m.id;

У меня есть индекс для (message_id, date) втаблица статусов.Запрос занимает у меня 8 секунд - и я бы хотел его улучшить.

У вас есть идеи?Я думал об использовании материализованного представления - но у меня возникли проблемы с его использованием (выполнение обновления заняло у меня навсегда) - какие наилучшие практики мне следует знать?Это даже рекомендуется?

Большое спасибо, комета.

edit: например,

messages содержит:

id    data
0     'aa'
1     'bb'

message_status содержит:

id    message_id      date       type
1000     0          11/11/18     'new'
1001     0          15/11/18     'sent'
1003     0          2/12/18      'done'
1004     1          11/11/18     'new'
1005     1          15/11/18     'sent'

результат должен быть:

id    data    creation_date      first_type    cur_status_date   cur_status_type
0     'aa'    11/11/18            'new'           2/12/18          'done'
1     'bb'    11/11/18            'new'           15/11/18         'sent'

1 Ответ

0 голосов
/ 02 декабря 2018

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

select m.*,
       (select ms.status
        from mesasge_status ms
        where ms.message_id = m.id
        order by ms.date asc
        limit 1
       ) as first_status,
       (select ms.status
        from mesasge_status ms
        where ms.message_id = m.id
        order by ms.date desc
        limit 1
       ) as last_status
from messages m;

Это должно как минимум приблизиться к выполнению того, что выкажется, хочу.Если message_status имеет индекс для (message_id, date), то это может соответствовать вашим целям производительности.

РЕДАКТИРОВАТЬ:

Если вы хотите более одного столбца, вы можете использовать кортежи - или более реалистично, боковые соединения:

select m.*, ms_first.*, ms_last.*
from messages m cross join lateral
     (select . . .
      from mesasge_status ms
      where ms.message_id = m.id
      order by ms.date asc
      limit 1
     ) ms_first cross join lateral
      (select . . .
      from mesasge_status ms
      where ms.message_id = m.id
      order by ms.date desc
      limit 1
     ) ms_last;
...