【问题标题】:VACUUM on Redshift (AWS) after DELETE and INSERT删除和插入后 Redshift (AWS) 上的 VACUUM
【发布时间】:2014-06-19 01:49:52
【问题描述】:

我有一个如下表(简化示例,我们有 60 多个字段):

CREATE TABLE "fact_table" (
  "pk_a" bigint                 NOT NULL ENCODE lzo,
  "pk_b" bigint                 NOT NULL ENCODE delta,
  "d_1"  bigint                 NOT NULL ENCODE runlength,
  "d_2"  bigint                 NOT NULL ENCODE lzo,
  "d_3"  character varying(255) NOT NULL ENCODE lzo,
  "f_1"  bigint                 NOT NULL ENCODE bytedict,
  "f_2"  bigint                     NULL ENCODE delta32k
)
DISTSTYLE KEY
DISTKEY ( d_1 )
SORTKEY ( pk_a, pk_b );

表格按高基数维度分布。

表格按时间顺序递增的一对字段排序。

该表包含超过 20 亿行,并使用约 350GB 的磁盘空间,都是“每个节点”。


我们的每小时内务管理涉及更新一些最近的记录(在表的最后 0.1% 内,基于排序顺序)并插入另外 100k 行。

无论我们选择何种机制,对表进行 VACUUM 处理都会变得过于繁琐:
- sort 步骤需要几秒钟
- merge 步骤需要 6 多个小时

我们可以从SELECT * FROM svv_vacuum_progress; 看到所有 20 亿行正在合并。即使前 99.9% 完全不受影响。


我们的理解是合并应该只影响:
1. 删除记录
2. 插入记录
3.以及从(1)或(2)到表尾的所有记录


我们尝试了DELETE and INSERT 而不是UPDATE,现在DML 步骤明显更快。但是VACUUM 仍然合并了所有 20 亿行。

DELETE FROM fact_table WHERE pk_a > X;
-- 42 seconds

INSERT INTO fact_table SELECT <blah> FROM <query> WHERE pk_a > X ORDER BY pk_a, pk_b;
-- 90 seconds

VACUUM fact_table;
-- 23645 seconds

事实上,VACUUM 合并了所有 20 亿条记录,即使我们只是将最后 746 行从表的末尾剪掉。


问题

对于如何避免这种巨大的VACUUM 开销,并且只有MERGE 出现在表格的最后 0.1% 上,是否有人有任何建议?

【问题讨论】:

  • 您是否考虑过用最近的 0.1% 创建另一个表,进行合并,然后删除/重新插入这些行?
  • @GordonLinoff - 主表上的删除/重新插入仍然存在问题。类似的方法(我们希望不需要) 是手动分区; fact_35 保存最近 35 天的数据(我们预计会波动的窗口),fact_hist 保存所有旧数据(我们希望稳定),以及将 UNION ALL 放在一起的视图。然后,我们每小时的内务管理将在一个小约 30 倍的表上工作,每晚将 1 天的数据“转移”到主表中。 (仅在 fact_hist 上插入,从不删除。) 但这会对 UNIONed 视图上的查询产生不良影响。
  • 您还可以考虑使用每小时(或每天)的表格,并将它们与视图或简单地在相关时间范围内的查询合并。
  • @guy - 这在功能上与我在评论中已经描述的没有什么不同,因此仍然会对查询性能产生同样的不良影响。
  • 我在 AWS 论坛上发现了这个问题。 AWS 的某个人正在对其进行调查。注意:AWS 中的DELETE 不会删除行,而是将它们标记为已删除。这就是为什么需要VACUUM 来回收磁盘空间的原因。将VACUUM 运行为DELETE ONLYSORT ONLY 有什么区别吗?我无法弄清楚排序和合并步骤是否仅针对其中一个选项发生。

标签: sql amazon-web-services amazon-redshift


【解决方案1】:

您多久抽空一次桌子?持续时间长对您有何影响?我们的负载处理在 VACUUM 期间继续运行,我们从未遇到过任何性能问题。基本上不需要多长时间,因为我们只是继续运行 BAU。

我还发现我们不需要经常清空我们的大桌子。一周一次就足够了。您的用例可能对性能非常敏感,但我们发现查询时间在正常变化范围内,直到表超过 90% 未排序。

如果您发现存在显着的性能差异,您是否考虑过使用最近和历史表(如果需要,在 UNION 视图中)?这样您就可以快速 VACUUM 小“最近”表。

【讨论】:

    【解决方案2】:

    无法在 cmets 部分修复它,因此将其发布为答案

    我认为现在,如果时间序列表中的 SORT 键相同,并且您有一个 UNION ALL 视图作为时间序列视图并且性能仍然很差,那么您可能希望有一个带有显式过滤器的时间序列视图结构作为

    create or replace view schemaname.table_name as 
    select * from table_20140901 where sort_key_date = '2014-09-01' union all 
    select * from table_20140902 where sort_key_date = '2014-09-02' union all .......
    select * from table_20140925 where sort_key_date = '2014-09-25';
    

    还要确保在每次加载后在排序键上收集所有这些表的统计信息,并尝试对其运行查询。如果您使用任何过滤器值,它应该能够将任何过滤器值下推到视图中。加载后一天结束,只需在当天的表上运行 VACUUM SORT ONLY 或完全真空,这应该会快得多。

    如果您在上述测试后仍然遇到任何问题,请告诉我。

    【讨论】:

    • 你是对的,RedShift 在这种情况下表现最好,但是当使用连接完成过滤时它仍然会出错,我在电话中与他们的一位产品经理和工程师讨论过。这是一个示例SELECT dimension.label, SUM(fact.x) FROM fact, dimension WHERE fact.fk = dimension.id AND dimension.label = 'FooBar' GROUP BY dimension.label - 即使“时间序列”表由 fk 排序,并且即使使用显式 WHERE 子句作为优化器提示,它也会产生全表扫描。
    • 是的。我们也在等待 Redshift 的修复,以便在 Join for Time series 视图中推送过滤器。但它有多糟糕,它运行了多少分钟?如果 fact.fk 是事实表上的 dist 键,那么它应该不会那么糟糕。在很多情况下,当优化器出现问题时,我们会尝试首先从子查询或带有 dist 键的查询的一部分中创建一个临时表,然后在第二个查询中使用它和剩余部分。
    • 我认为你的意思是排序键;通过 dist-key 将数据划分为“时间序列”会导致偏差。在“多长时间”方面;它对每个底层分区表进行全表扫描。我们有超过 20 亿行,如果没有手动分区需要几秒钟的查询需要几分钟。至于临时表;大多数报告套件不允许您以这种方式进行干预;我们的主要示例是 MDX 分析工具。
    猜你喜欢
    • 1970-01-01
    • 2018-09-19
    • 2013-05-05
    • 1970-01-01
    • 1970-01-01
    • 2016-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多