Проблемы производительности SQL с внутренним выбором в Postgres для табличного отчета - PullRequest
0 голосов
/ 24 октября 2019

Использование Postgres DB:

У меня есть приложение для опроса, в котором пользователи вводят действия и отвечают на вопросы об их действиях. Сам опрос называется RECALLS_T, введенные события - EVENTS_T, а ответы - ANSWERS_T. Ответы предназначены для заданных вопросов об активности, которые хранятся в ACTIVITY_QUESTIONS_T и отображаются в Lookup (LOOKUP_T).

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

Пример (сначала простые плоские вещи, затем сложные табличные):

RecallID | RecallDate | Event |..| WalkAlone | WalkWithPartner |..| ExerciseAtGym
256      | 10-01-19   | Exrcs |..| NULL      | NULL            |..| yes
256      | 10-01-19   | Walk  |..| yes       | NULL            |..| NULL
256      | 10-01-19   | Eat   |..| NULL      | NULL            |..| NULL
257      | 10-01-19   | Exrcs |..| NULL      | NULL            |..| yes

Мой SQL имеет внутренний выбор для табличной таблицыстолбцы, основанные на ответах, и выглядят так:

select 
-- Easy flat stuff first
r.id as recallid, r.recall_date as recalldate, ... ,

-- Example of Tabulated Columns:
(select l.description from answers_t ans, activity_questions_t aq, lookup_t l 
where l.id=aq.answer_choice_id and aq.question_id=13 
and aq.id=ans.activity_question_id and aq.activity_id=27 and ans.event_id=e.id) 
     as transportationotherintensity,
(select l.description from answers_t ans, activity_questions_t aq, lookup_t l
where l.id=66 and l.id=aq.answer_choice_id and aq.question_id=14
and aq.id=ans.activity_question_id and ans.event_id=e.id) 
     as commutework,
(select l.description from answers_t ans, activity_questions_t aq, lookup_t l
where l.id=67 and l.id=aq.answer_choice_id and aq.question_id=14 and aq.id=ans.activity_question_id and ans.event_id=e.id) 
     as commuteschool,
(select l.description from answers_t ans, activity_questions_t aq, lookup_t l
where l.id=95 and l.id=aq.answer_choice_id and aq.question_id=14 and aq.id=ans.activity_question_id and ans.event_id=e.id) 
     as dropoffpickup,

SQL работает, и отчет обрабатывается, , но производительность плохая . Я проверил, что это пропорционально плохо: для определенного предмета, который мог бы это исправить, не было волшебной пули. Каждый Inner Select способствует плохой производительности. Результирующий набор из 1000 строк занимает 15 секунд, но должен занимать не более 2-3 секунд.

Обратите внимание, что эти индексы уже существуют:

  • ANSWERS_T: on ACTIVITY_QUESTION_ID, EVENT_ID
  • EVENTS_T: вкл. RECALL_ID
  • ACTIVITY_QUESTIONS_T: вкл. ACTIVITY_ID, QUESTION_ID, ANSWER_CHOICE_ID

Есть что-то, что я делаю не так с этими внутренними выборами?

1 Ответ

2 голосов
/ 24 октября 2019

Чтобы подвести итоги вопросов, вы хотите использовать условную агрегацию. В Postgres вы используете:

select ans.event_id,
       max(l.description) filter (where aq.question_id = 13 and and aq.activity_id = 27) as transportationotherintensity
       max(l.description) filter (where l.id = 66 and aq.question_id = 14 and and aq.activity_id = 67) as commutework,
       . . .
from activity_questions_t aq join
     lookup_t l 
     on l.id = aq.answer_choice_id join
     answers_t ans
     on aq.id = ans.activity_question_id
group by ans.event_id
...