选择性谓词下推查看

Posted

技术标签:

【中文标题】选择性谓词下推查看【英文标题】:Selective Predicate Pushdown To View 【发布时间】:2022-01-01 23:29:12 【问题描述】:

我有一个经常更新的大型列存储表。我不会将更新直接摄取到源表中,因为在大多数情况下,这会导致少量更新导致全表微分区重建。相反,我将更新流式传输到更新表,并在查询时将两者结合起来。在实践中,这很有效。

所以把事情简化一下,我会把它放在一个视图中users_view

CREATE OR REPLACE VIEW users_view AS (
    SELECT * FROM users
    UNION ALL 
    SELECT * FROM user_changes
    QUALIFY ROW_NUMBER() OVER(
        PARTITION BY id 
        ORDER BY last_updated_at DESC
    ) = 1
)

users 表和user_changes 表具有相同的方案以及一些分区配置。这样,我可以在视图上使用谓词下推来仅选择正确分区内的用户。假设这是account_id

SELECT * FROM users_view
WHERE account_id = 1234

但是users 表比user_changes 表大很多,我想将更多谓词下推到users 表,而不将其他谓词下推到user_changes 表。为什么?因为users 表上的匹配虽然准确率为 98%,但存在误报/误报。需要来自user_changes 的详细信息才能正确设置记录。这在视图之外看起来是这样的:

SELECT * FROM (
    SELECT * FROM users
    WHERE account_id = 1234 AND city = 'Chicago'
    UNION ALL 
    SELECT * FROM user_changes
    WHERE account_id = 1234
    QUALIFY ROW_NUMBER() OVER(
        PARTITION BY id 
        ORDER BY last_updated_at DESC
    ) = 1
)
WHERE account_id = 1234 AND city = 'Chicago'

虽然看起来很糟糕,但它的性能要高得多。所有条件都可以应用于更大的users 表,但只有不变的条件可以应用于users_changes 表。即用户可以更改城市,但用户不能更改帐户。联合后所有条件的第二次运行是捕获 user_changes 引入的任何更改。

这写起来很麻烦,当查询变得复杂并且涉及到查询构建器时更是如此。因此,我正在寻找方法来说服 sql 规划器跳过我的 user_changes 表上某些谓词的谓词下推,而无需像这样格式化查询。最好有风景。

伪 SQL。伪 SQL。伪 SQL

在我最疯狂的梦想中,我可以告诉查询规划器在哪里可以使用分区谓词,以及在哪里可以使用非分区谓词。

CREATE OR REPLACE VIEW users_view AS (
    SELECT * FROM (
        SELECT * FROM users
        %PARTITION_PREDICATES%
        %NON_PARTITION_PREDICATES%

        UNION ALL 

        SELECT * FROM user_changes
        %PARTITION_PREDICATES%

        QUALIFY ROW_NUMBER() OVER(
            PARTITION BY id 
            ORDER BY last_updated_at DESC
        ) = 1
    )
    %PARTITION_PREDICATES%
    %NON_PARTITION_PREDICATES%
)

SELECT * FROM users_view
WHERE account_id = 1234 AND city = 'Chicago'

有什么疯狂的想法吗?

【问题讨论】:

您是否正在使用已经硬编码的谓词创建视图?如果我的问题正确,您想简化查询构建,以便仅在查询结束时应用谓词(仍在视图内)? 理想情况下,我希望将视图视为一个知道如何将正确谓词应用于每个表的黑盒。我想将完整的谓词应用于我的users 表,但要手动选择要应用于user_changes 表的谓词。所以是的——这将是为了简化查询构建过程。 【参考方案1】:

您可以添加额外的列 src 来确定源表并在 CASE 中包装谓词:

select * from
(
SELECT u.*, 'users' as src FROM users u
union all
SELECT uc.*, 'users_changes' as src FROM users_changes uc
) 
WHERE --applied only to users
      case when src  = 'users' 
                 then city = 'Chicago' --predicate wrapped in case
           else true
       end
  --applied to all
  AND account=12345 

【讨论】:

非常酷的主意!谢谢! @micah 您可以使用 AND 或 OR 将所有谓词包装在单个 CASE 中:then city = 'Chicago' AND one_more_condition AND some_other_condition

以上是关于选择性谓词下推查看的主要内容,如果未能解决你的问题,请参考以下文章

谓词下推

聊聊谓词下推的事

什么是谓词下推,看这一篇就够了

如何防止谓词下推?

创建没有下推谓词的动态框架问题

谓词下推 vs On 子句