Как оптимизировать sql где = (выбрать из same_table) - PullRequest
0 голосов
/ 28 января 2020

У меня есть запрос PostgreSQL, и мне интересно, есть ли способы его оптимизации.

Основным узким местом в запросе является подзапрос, я думаю.

select social_status, count(*)
from client
where 1 = 1
  and social_status = (select social_status from client where id = 1)
  and created_at between '2018-09-10 06:05:41'::timestamp - interval '14 day' and '2018-09-10 06:05:41'::timestamp
group by social_status

Также я попытался заменить = на in, но это ничего не изменило.

Я пытался использовать объединение, но ничего не возвращает:

select a.social_status, count(*)
from client a
JOIN client b
     ON a.id = b.id
where 1 = 1
   and b.id = 1
  and a.social_status = b.social_status
  and a.created_at between '2018-09-10 06:05:41'::timestamp - interval '14 day' and '2018-09-10 06:05:41'::timestamp
group by a.social_status

В данный момент это занимает около 13-19 секунд.

Объяснение (анализ, буферы, форматирование текста) результат:

QUERY PLAN
GroupAggregate  (cost=8.44..206659.09 rows=12 width=17) (actual time=23584.356..23584.357 rows=1 loops=1)
  Group Key: a.social_status
  Buffers: shared hit=8737 read=183781
  I/O Timings: read=22802.316
  InitPlan 1 (returns $0)
    ->  Index Scan using client_id_index on client  (cost=0.42..8.44 rows=1 width=9) (actual time=1.405..1.407 rows=1 loops=1)
          Index Cond: (id = 1)
          Buffers: shared hit=1 read=3
          I/O Timings: read=1.374
  ->  Seq Scan on client a  (cost=0.00..206645.81 rows=943 width=9) (actual time=202.157..23582.677 rows=2323 loops=1)
        Filter: ((created_at >= '2018-08-27 06:05:41'::timestamp without time zone) AND (created_at <= '2018-09-10 06:05:41'::timestamp without time zone) AND ((social_status)::text = ($0)::text))
        Rows Removed by Filter: 812931
        Buffers: shared hit=8737 read=183781
        I/O Timings: read=22802.316
Planning Time: 0.217 ms
Execution Time: 23584.460 ms

1 Ответ

1 голос
/ 28 января 2020

Вы можете попробовать использовать оконные функции:

select social_status, count(*)
from (select c.*,
             max(social_status) filter (where id = 1) over () as social_status_1
      from client c
     ) c
where social_status = social_status_1 and
      created_at between '2018-09-10 06:05:41'::timestamp - interval '14 day' and
                         '2018-09-10 06:05:41'::timestamp
group by social_status;

Для этого запроса вам нужен индекс для client(id, social_status) и client(created_at, social_status).

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