существует (A) и не существует (negA) против пользовательской агрегации - PullRequest
0 голосов
/ 17 сентября 2018

Часто мне приходится выбирать клиентов, которые выполнили {набор критериев A} транзакций, а не ДРУГОЙ тип транзакций.Пример данных:

create table customer (name nvarchar(max))
insert customer values
('George'),
('Jack'),
('Leopold'),
('Averel')

create table trn (id int,customer nvarchar(max),product char(1))
insert trn values
(1,'George','A'),
(2,'George','B'),
(3,'Jack','B'),
(4,'Leopold','A')

Допустим, мы хотим найти всех покупателей, которые купили продукт «А», а не что-либо еще (в данном случае, B).Наиболее типичный способ сделать это включает в себя соединение таблицы транзакций с самим собой:

select * from customer c
where exists(select 1 from trn p where p.customer=c.name and product='A')
and not exists(select 1 from trn n where n.customer=c.name and product='B')

Мне было интересно, есть ли лучший способ сделать это.Имейте в виду, что таблица транзакций обычно должна быть огромной.

Как насчет этой альтернативы:

select * from customer c
where exists
(
    select 1
    from trn p
    where p.customer=c.name
    group by p.customer
    having max(case when product='B' then 2 when product='A' then 1 else 0 end)=1
)

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

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

Вы можете попробовать следующее утверждение. Это может быть быстрее, чем ваши заявления при определенных обстоятельствах, так как он всегда будет определять сначала клиентов с транзакциями продукта А, а затем ищет только этих клиентов, если есть транзакции для других продуктов. Если какая-то выгода действительно зависит от данных и индексов ваших реальных таблиц, так что вы должны попробовать.

WITH customerA AS (SELECT DISTINCT customer FROM trn WHERE product = 'A')
SELECT DISTINCT customer.*
FROM customerA JOIN customer ON customerA.customer = customer.name
WHERE not exists(select 1 from trn n where n.customer = customerA.customer and
product <> 'A')
0 голосов
/ 17 сентября 2018

Вам необходимо проверить производительность на ваших данных.Если у вас есть индекс для trn(customer, product), тогда exists обычно будет иметь очень разумную производительность.

Это особенно верно, когда вы используете таблицу customers.

Насколько хорошосравнивается версия агрегации?Во-первых, лучшая агрегация будет выглядеть следующим образом:

select customer
from trn
where product in ('a', 'b')
group by customer
having min(product) = 'a' and max(product) = 'b';

Если у вас есть индекс на product - и есть много продуктов (или мало клиентов, у которых есть "a" и "b"), тогдаэто может быть быстрее, чем версия not exists.

В целом, я рекомендую использовать group by, хотя его производительность не всегда является лучшей для нескольких продуктов.Почему?

  • Использование предложения having достаточно гибко для обработки всех различных условий «набор в наборе».
  • Добавление дополнительных условий не имеет большого значениявлияние на производительность.
  • Если вы не используете таблицу клиентов, а вместо этого делаете что-то вроде (select distinct customer from trn), то версия exists / not exists, вероятно, будет дороже.

Этосказал, я выступаю за использование group by и having, потому что это более гибкий.Это означает, что при правильных обстоятельствах следует использовать другие решения.

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