UNION
может использоваться для объединения 2 наборов данных И, одновременно удаляя дублирующиеся строки.UNION ALL
может использоваться для объединения 2 наборов данных (а затем останавливается).Таким образом, UNION ALL
избегает накладных расходов на поиск и удаление дублированных строк, поэтому это быстрее.
В пределах вашего исходного общего выражения таблицы (cte) the_comments
вы заставляете каждую сторонуобъединения для использования различных констант, например,
select *
from (
select 1 as id, 'OFFER' AS source
union
select 1 as id, 'DIRECT' AS source
) d
;
result:
id source
---- --------
1 DIRECT
1 OFFER
Несмотря на то, что идентификатор 1 находится в обеих сторонах этого объединения, из-за различных констант 2 строки возвращаются в этом примере запроса.Поэтому, пожалуйста, используйте UNION ALL
.
Несмотря на удобство select *
, его не следует использовать в представлениях (хотя существуют аргументы в обоих направлениях, например, здесь ).Возможно, это было сделано для упрощения вопроса, но я надеюсь, что он не используется буквально, как видно.Если целью представления является возвращение только 4 столбцов, укажите только эти столбцы.
Несмотря на то, что вам нужен product_id в выводе, это может быть получено из offers.product_id
или products_comments.product_id
, так что вы на самом деле этого не делаетенужно присоединиться к таблице продуктов.Нет необходимости присоединяться к таблице продуктов после cte.
Поскольку мы сейчас используем UNION ALL
, я не вижу никакой выгоды от использования SELECT DISTINCT ON(...)
, я подозреваю этопросто накладные расходы, которые могут быть удалены.Очевидно, я не могу это проверить, и это может зависеть исключительно от ваших функциональных требований.Также обратите внимание, что SELECT DISTINCT ON(...)
удалит source
, который вы так тщательно представили, например,
select distinct on (id) id, source
from (
select 1 as id, 'OFFER' AS source
union
select 1 as id, 'DIRECT'AS source
) d
;
result:
id source
---- --------
1 DIRECT
Не включайте предложение order by
в любом представлении, только заказывайте «окончательный запрос».Другими словами;если вы создаете представление, вы, вероятно, будете использовать его в нескольких других запросах.Каждый из этих запросов, скорее всего, будет иметь свое собственное предложение where и будет нуждаться в разных порядках результата.Если вы заказываете представление, вы просто потребляете циклы процессора, а потом отказываетесь от этих усилий позже.Поэтому, пожалуйста, удалите заказ по предложению.
Я бы очень хотел предложить другой подход к заключительному предложению where, но, поскольку я не очень разбираюсь с JSON, у меня нет достаточного опыта, чтобы предложитьальтернатива.Однако использование функций для данных в предложении where почти всегда является причиной низкой производительности, особенно в том случае, если он обычно исключает доступ к индексам столбцов, участвующих в этих функциях.Поиск более эффективного способа исключения исключений из комментариев, вероятно, приведет к наибольшему улучшению производительности ваших запросов.
Итак, мои предложения приведут к следующему:
WITH the_comments
AS (
SELECT
comments.id
, comments.name
, 'OFFER' AS source
, offers.product_id AS product_id
FROM comments
JOIN activities_comments ON activities_comments.comment_id = comments.id
JOIN activities ON activities.id = activities_comments.activity_id
JOIN offers ON offers.activity_id = activities.id
UNION ALL
SELECT
comments.id
, comments.name
, 'DIRECT' AS source
, products_comments.product_id AS product_id
FROM comments
JOIN products_comments ON products_comments.comment_id = comments.id
)
SELECT
the_comments.id
, the_comments.name
, the_comments.source
, the_comments.product_id
FROM the_comments
/* perhaps raise a separate question on this bit */
WHERE NOT to_json(products.ignored_comment_ids)::jsonb @> the_comments.id::jsonb