Создать представление базы данных, объединяющее несколько таблиц - PullRequest
0 голосов
/ 08 октября 2018

Я хотел бы получить помощь в создании представления базы данных.Моя схема БД выглядит следующим образом:

products            (id, ignored_comments_ids (array))
activities          (id)
comments            (id)
activities_comments (activity_id comment_id)
products_comments   (product_id, comment_id)
offers              (product_id, activity_id)

Теперь мне нужно создать представление для комментариев всех продуктов с пользовательским столбцом с именем source:

  • source = 'ПРЕДЛОЖЕНИЕ ': комментарии поступают от products.offers.activities.comments ассоциации
  • source =' DIRECT ': комментарии поступают от products.comments ассоциации

    Кроме того, представление должно исключать комментарии из products.ignored_comments_ids

Как мне это сделать?В представлении должны быть product_id, source и все столбцы из таблицы comments.

Я получил следующее представление, как его улучшить?

CREATE OR REPLACE VIEW all_comments AS
  WITH the_comments AS (
    SELECT
      comments.*,
      'OFFER'     AS source,
      products.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
    JOIN products            ON products.id = offers.product_id
  UNION
    SELECT
      comments.*,
      'DIRECT'    AS source,
      products.id AS product_id
    FROM comments
    JOIN products_comments ON products_comments.comment_id = comments.id
    JOIN products          ON products.id = products_comments.product_id
  )
  SELECT DISTINCT ON (the_comments.id)
    the_comments.id,
    the_comments.name,
    the_comments.source,
    the_comments.product_id
  FROM the_comments
  JOIN products ON products.id = the_comments.product_id
  WHERE NOT to_json(products.ignored_comment_ids)::jsonb @> the_comments.id::jsonb
  ORDER BY the_comments.id;

1 Ответ

0 голосов
/ 11 октября 2018

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...