选择性谓词下推查看

Selective Predicate Pushdown To View

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

所以简化事情,我将把它放在一个视图中 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 table 和 user_changes table 具有相同的方案以及一些分区配置。这样我就可以在视图上使用谓词下推,仅对正确分区内的 select 用户。假设这是 account_id.

SELECT * FROM users_view
WHERE account_id = 1234

但是 users table 比 user_changes table 大很多,我想将更多谓词下推到 users table 而不将额外的谓词下推到 user_changes table。为什么?因为 users table 上的匹配虽然准确率为 98%,但 positives/negatives 是错误的。需要来自 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 table,但只有不变的条件才能应用于 users_changes table。即用户可以更改城市,但用户不能更改帐户。联合后所有条件的第二个 运行 是捕获 user_changes 引入的任何更改。

这写起来很麻烦,而且随着查询变得复杂和查询构建器的参与,更是如此。所以我正在寻找说服 sql 计划者跳过我的 user_changes table 上某些谓词的谓词下推的方法,而无需像这样格式化查询。最好有风景。

PSUEDOSQL。伪装 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'

有什么疯狂的想法吗?

您可以添加额外的列 src 以确定来源 table 并在 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