Выбор между использованием счетчика с фильтром и изменением условия - PullRequest
2 голосов
/ 02 мая 2020

Есть 2 таблицы, video и category.

create table category (
    id integer primary key,
    name text
);

create table video (
    id integer primary key,
    category_id integer references category (id),
    quality text
);

insert into category (id, name) values (1, 'Entertainment');
insert into category (id, name) values (2, 'Drawing');

insert into video (id, category_id, quality) values (1, 1, 'sd');
insert into video (id, category_id, quality) values (2, 1, 'hd');
insert into video (id, category_id, quality) values (3, 1, 'hd');

Я могу получить список всех категорий с количеством всех видео.

select category.id, category.name, count(video)
from category left outer join video
on (category.id = video.category_id)
group by category.id;

результат

 id |     name      | count 
----+---------------+-------
  2 | Drawing       |     0
  1 | Entertainment |     3
(2 rows)

Чтобы получить все категории с количеством HD-видео, можно использовать оба эти запроса.

count с фильтром

select
category.id,
category.name,
count(video) filter (where video.quality='hd')
from category left outer join video
on (category.id = video.category_id)
group by category.id;

результат

 id |     name      | count 
----+---------------+-------
  2 | Drawing       |     0
  1 | Entertainment |     2
(2 rows)

в

select
category.id,
category.name,
count(video)
from category left outer join video
on (category.id = video.category_id and video.quality='hd')
group by category.id;

результат

 id |     name      | count 
----+---------------+-------
  2 | Drawing       |     0
  1 | Entertainment |     2
(2 rows)

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

1 Ответ

2 голосов
/ 02 мая 2020

Второй запрос несколько эффективнее, поскольку предикат on для join уменьшает количество строк ранее, тогда как первый запрос сохраняет их все, а затем использует фильтр агрегатной функции. Я бы порекомендовал второй запрос.

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

select
    category.id,
    category.name,
    count(*) filter (where video.quality='hd') no_hd_videos,
    count(*) filter (where video.quality='sd') no_sd_videos
from category 
left outer join video on category.id = video.category_id
group by category.id;
...