【问题标题】:How can I save computation by reusing calculated result set in MERGE如何通过重用 MERGE 中的计算结果集来节省计算
【发布时间】:2016-11-02 20:09:34
【问题描述】:

我想在我需要每天运行的 SQL 连接语句中重用以前计算的结果集。例如,我有两个表:table_A 和 table_B,它们共享一个公共键,例如 ckey。我想在我的查询中使用 LEFT JOIN 来查找 table_A 中的数据记录,这些数据记录映射到基于 ckey 的 table_B 中的数据记录:

SELECT a*, b*
FROM table_A as A
LEFT JOIN table_B as B
ON A.ckey = B.ckey

然后我想将上述连接中不匹配的行存储在一个单独的表中,例如table_C,以便我可以定期查看它们并稍后更新 table_B 内容。对于table_A和table_B之间匹配的那些,我想将它们存储在一个新表中(我们称之为table_C)。为此,我希望使用 WITH 子句来临时存储结果集,如下所示:

CREATE TABLE IF NOT EXISTS table_C (ckey_to_review VARCHAR(10));

WITH left_join_result AS(
SELECT a*, b.ckey as b_ckey
FROM table_A as A
LEFT JOIN table_B as B
ON A.ckey = B.ckey),

non_matchable_data AS(
SELECT distinct ckey
FROM left_join_result AS C
WHERE b_ckey IS NULL),

matchable_data AS(
SELECT *
FROM left_join_result AS C
WHERE b_ckey IS NOT NULL)

/* use MERGE to upsert newly found unmatchable items */
MERGE INTO table_C AS t
USING non_matchable_data AS s
ON t.ckey_to_review = s.ckey
WHEN MATCHED THEN UPDATE SET ckey_to_review = s.ckey
WHEN NOT MATCHED THEN 
    INSERT (ckey_to_review)
    VALUES (s.ckey)

/* then use data from 'matchable_data' above for something other procedures */

我后来才知道WITH clause are only allowed to be used with SELECT statement。为了提供更具体的上下文,我使用 Vertica 来执行此操作,以防有针对此问题的特定 Vertica 解决方案。我只拥有 SQL 的基本知识,所以我确信有某种设计模式可以指导我有效地做我想做的事情(也就是说,不需要我更多地调用 LEFT JOIN一次又一次地重复使用来自 LEFT JOIN 的结果集)。

【问题讨论】:

    标签: sql vertica


    【解决方案1】:

    老实说,我认为你想多了。

    所以要准确回答您的问题,您可以只创建本地临时表而不是使用withCREATE LOCAL TEMP TABLE 它将在您的会话中可用。顺便说一句,除非你specifically enable an option,否则with 是一个内联视图,没有具体化。

    也就是说,我真的认为以下内容会很好。如果您真的希望它高效,那么您将更关心如何对数据进行分段和排序以创建本地合并连接。

    SELECT ckey
    FROM table_B
    MINUS
    SELECT ckey
    FROM table_A
    

    SELECT ckey
    FROM table_B
    INTERSECT
    SELECT ckey
    FROM table_A
    

    【讨论】:

    • 感谢您的建议。我将尝试使用本地临时表。我关心代码效率的原因是因为每天要处理大约 5 亿行数据。但是您是对的,数据分段的方式可能比连接代码本身更重要。谢谢!
    • 这不能通过“插入/忽略或插入...重复键更新”样式设置来完成吗?第一次将是一个繁重的过程,但以后只会添加新项目。我想这也取决于你的 sql 风格,因为减号不是 Mysql 的选项。
    • @cora 在 Vertica 中没有插入忽略之类的东西。 Vertica 是一个没有这些功能的柱状 OLAP 样式数据库。
    【解决方案2】:

    因此,您正在寻找的内容在 DataWarehouse(或 DataMart)世界中很常见……您正在寻找一种增量加载策略,其中有多种方法。

    insert into [matched] (PK)
    select key from table1 join table2 on key
    where key not in (select PK from [Matched])
    

    根据您对 5 亿条记录的评论,这将是第一次会很糟糕……增量应该更少。

    您还可以考虑各种其他策略:

    • nolocks(取决于源表的填充方式)以减少锁争用

    • 分块以减少事务大小(日志文件增长等)

    • maxdop 用于管理吞吐量、执行时间和资源负载

    【讨论】:

    • 感谢您的建议! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 2014-04-01
    • 2022-08-22
    • 2020-07-12
    相关资源
    最近更新 更多