我想在创建数据库 View 方面获得一些帮助。 我的数据库架构如下所示:
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
的自定义列创建所有产品评论的 View :
source
= 'OFFER': 评论来自products.offers.activities.comments
关联来源
= '直接': 来自products.comments
协会的评论此外,该 View 应排除来自
的评论products.ignored_comments_ids
我该怎么做?该 View 必须包含 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;
最佳答案
UNION
可用于合并 2 组数据,AND,同时它会删除重复的行。 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
即使 id 1 在该联合的两边,由于常量不同,该示例查询返回 2 行。所以请改用UNION ALL
。
尽管 select *
很方便,但不应在 View 中使用它(尽管两种方式都有参数,例如 here )。也许这样做是为了简化问题,但我希望它不会像看到的那样按字面意思使用。如果 View 的目的是仅返回 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
不要在任何 View 中包含 order by
子句,仅排序“最终查询”。换句话说;如果您创建了一个 View ,那么您很可能会在其他几个查询中使用它。这些查询中的每一个都可能有自己的 where 子句并且需要不同的结果顺序。如果您订购 View ,您只是在消耗 cpu 周期,然后在稍后放弃该工作。所以,请删除 order by 子句。
我非常想为最后的 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
关于sql - 创建连接多个表的数据库 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52696909/