[英]PostgreSQL 9.6 - INSERT ON CONFLICT DO UPDATE WHERE RETURNING
我创建并自动化了一个自定义工作流程,以便热切地同步一系列物化视图。 在尝试了几种不同的方法(针对一对多关系)后,我发现最可靠的同步工作流程是删除可能已受影响的所有记录,然后插入新记录。
DELETE FROM
some_materialized_view
WHERE
set_of_records_key = some_value;
INSERT INTO
some_materialized_view
SELECT
*
FROM
some_query_generating_some_materialized_view;
注意:some_query_generating_some_materialized_view是一个复杂的读取操作,需要执行非常少量的资源。 另外,some_materialized_view被多个外键和其他约束严重索引。
这感觉非常沉重。 此工作流程带有过多的删除和插入操作,这些操作通常是不必要的,因为某些已删除的记录可能相同或类似,足以成为UPDATE的候选者。
我更喜欢以下内容:
DELETE FROM
some_materialized_view
USING
(
SELECT
unique_key
FROM
some_materialized_view
WHERE
set_of_records_key = some_value
EXCEPT
INSERT INTO
some_materialized_view
SELECT
*
FROM
some_query_generating_some_materialized_view
ON CONFLICT (...) DO UPDATE
SET
foo = EXCLUDED.foo,
bar = EXCLUDED.bar,
...
WHERE
some_materialized_view <> EXCLUDED
RETURNING
unique_key
) AS sub_query
WHERE
some_materialized_view.unique_key = sub_query.unique_key;
问题出在ON CONFLICT ... DO UPDATE ... WHERE ... RETURNING
子句中。
正如这个问题所述: 如何在PostgreSQL中使用RETURNING和ON CONFLICT?
RETURNING子句仅返回受影响的记录。 因此,不会返回未受影响的记录,因此(在上面的示例中)不恰当地删除了。
似乎让RETURNING
实际返回所有记录的唯一方法是通过删除WHERE some_materialized_view <> EXCLUDED
子句来不必要地更新相同的记录,或者在另一个EXCEPT
子句中再次运行some_query_generating_some_materialized_view ...这两个选项也不理想。
那么,我错过了什么? 还有其他选择吗? 如果不是, 通常情况下 ,是否优先在不必要的UPDATE上执行复杂的,资源密集的读取操作(记住相关的索引维护和检查约束)?
注意:我不包括EXPLAIN ANALYZE
结果,因为这不是特定于单个查询,而是一般的问题。 为了可维护性和健全性,该项目需要保持一致,并且这种技术多次使用不同结构和用例的表(一些读重,另一些写重)。
WITH fresh AS ( -- workhorse: Called only and exactly once
SELECT <keyfields> -- *
FROM some_query_generating_some_materialized_view
)
,upd AS ( -- update existing rows
UPDATE some_materialized_view mv
SET foo = fr.foo, bar = fr.bar
FROM fresh fr
WHERE mv.<keyfields = fr.<keyfields>
RETURNING mv.<keyfields>
)
/*
, del AS (
no deletes ???
)
*/
-- insert non existing rows.
INSERT INTO some_materialized_view mv ( <targetfields> )
SELECT fr.<srcfields>
FROM fresh fr
WHERE NOT EXISTS (
SELECT *
FROM upd nx
WHERE nx.<keyfields> = fr.<keyfields>
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.