如何排除 Amazon Redshift 占用大量磁盘空间或用尽磁盘空间的问题?

3 分钟阅读
0

我遇到了 Amazon Redshift 占用大量磁盘空间或用尽磁盘空间的问题,想要排查此问题。

解决方案

占用大量磁盘空间错误可能取决于以下多种因素:

  • 分配和排序键
  • 查询处理
  • 带有 VARCHAR(MAX) 列的表
  • 高列压缩
  • 维护操作
  • 具有交叉联接的笛卡尔积
  • 最小表大小
  • 逻辑删除数据块
  • 复制大型文件

分配和排序键

查看表的分配样式、分配键和排序键选择。具有分配偏差的表(一个节点中的数据比另一个节点多)可能会导致磁盘节点空间用尽。如果表的分配样式为偏斜分配样式,则将分配样式更改为更统一的分配方式。请注意,分配和行偏斜可能会影响查询运行时的存储偏斜和中间行集。有关分配键和排序键的详细信息,请参阅 Amazon Redshift engineering’s advanced table design playbook: preamble, prerequisites, and prioritization

要确定分配键的基数,请运行以下查询:

SELECT <distkey column>, COUNT(*) FROM <schema name>.<table with distribution skew> GROUP BY <distkey column> HAVING COUNT(*) > 1 ORDER BY 2 DESC;

**注意:**要避免排序步骤,请在 ORDER BY 子句中使用 SORT KEY 列。排序步骤可能会占用过多的内存,从而导致磁盘满溢。有关更多信息,请参阅使用排序键

在筛选的结果集中,选择具有高基数的列以查看其数据分布。有关表的分布方式的详细信息,请参阅选择最佳分布方式

要查看分配键中的数据库块如何映射到集群,请使用 Amazon Redshift table_inspector.sql 实用程序

查询处理

查看分配给查询的所有内存。在处理查询时,中间查询结果可以存储在临时块中。如果没有足够的可用内存,则表会导致磁盘满溢。中间结果集未压缩,这会影响可用的磁盘空间。有关更多信息,请参阅分配给查询的内存不足

Amazon Redshift 默认为均匀分配的表结构,并且没有临时表的列编码。但是,如果您使用的是 SELECT...INTO 语法,请使用 CREATE 语句。有关更多信息,请参阅 Top 10 performance tuning techniques for Amazon Redshift。按照提示 6:解决临时表的低效使用下的说明进行操作。

如果为查询分配的内存不足,您可能会在 SVL_QUERY_SUMMARY 中看到一个步骤,其中 is_diskbased 显示的值为“true”。要解决此问题,请增加查询槽的数量,以便为查询分配更多内存。有关如何临时增加查询插槽的详细信息,请参见 wlm_query_slot_count调整 WLM 以运行混合工作负载。您还可以使用 WLM 查询监控规则来应对繁重的处理负载问题并识别 I/O 密集型查询。

带有 VARCHAR(MAX) 列的表

检查 VARCHAR 或 CHARACTER VARYING 列中是否有在数据存储在磁盘上时可能忽略的尾部空格。在查询处理过程中,尾部空格可占用内存中的全长(VARCHAR 的最大值为 65535)。最佳实践是使用尽可能小的列

要生成具有最大列宽的表格列表,请运行以下查询:

SELECT database, schema || '.' || "table" AS "table", max_varchar FROM svv_table_info WHERE max_varchar > 150 ORDER BY 2;

要标识和显示宽 VARCHAR 表列的实际宽度,请运行以下查询:

SELECT max(octet_length (rtrim(column_name))) FROM table_name;

在此查询的输出中,验证长度是否适合您的使用案例。如果列的最大长度超出了您的需求,将其长度调整为所需的最小大小。

有关表设计的更多信息,请查看设计表的 Amazon Redshift 最佳实践

高列压缩

使用 ANALYZE COMPRESSION 或使用 Amazon Redshift 中的自动表优化功能对所有列(排序键除外)进行编码。Amazon Redshift 提供列编码功能。使用此功能是最佳实践,它还可以提升读取性能并减少总体存储空间消耗。

维护操作

请确保定期分析和清理 Amazon Redshift 数据库中的数据库表。识别针对缺少统计信息的表运行的所有查询。阻止对缺少统计数据的表运行查询可使 Amazon Redshift 避免扫描不必要的表行。这还有助于优化您的查询处理。

**注意:**VACUUM 和 DEEP COPY 等维护操作使用临时存储空间进行分类操作,因此预计会出现磁盘使用量激增的情况。

例如,以下查询可帮助您识别 Amazon Redshift 中的过时统计信息:

SELECT * FROM svv_table_info WHERE stats_off > 10 ORDER BY size DESC;

此外,还可以使用 ANALYZE 命令查看和分析表统计信息。

有关维护操作的更多信息,请参阅 Amazon Redshift 分析和清空方案实用程序

具有交叉联接的笛卡尔积

使用查询的 EXPLAIN 计划查找笛卡尔积相关的查询。笛卡尔积具有不相关的交叉联接,可能会产生更多数据块。这些交叉联接可以提高内存利用率,并且会有更多的表溢出到磁盘。如果交叉联接不共享 JOIN 条件,则联接将生成两个表的笛卡尔积。然后,一个表的每一行都会联接到另一个表的每一行。

交叉联接还可以作为嵌套循环联接运行,这需要最长的处理时间。嵌套循环联接会导致整体磁盘使用量出现峰值。有关更多信息,请参阅发现具有嵌套循环的查询

最小表大小

同一个表在不同的集群中可能会具有不同的大小。然后,最小表大小由列数以及表中是否有 SORTKEY 及其切片数决定。如果您最近调整了 Amazon Redshift 集群的大小,您可能会看到整体磁盘存储空间发生了变化。这是由切片数量发生变化引起的。Amazon Redshift 还会对每个表所使用的表段进行计数。有关更多信息,请参阅为什么 Amazon Redshift 集群中的表使用的磁盘存储空间高于或低于预期?

逻辑删除数据块

当向 Amazon Redshift 表进行 WRITE 事务且存在并发读取时,将生成逻辑删除数据块。Amazon Redshift 在写入操作之前保留数据块,以保持并发读取操作的一致性。无法更改 Amazon Redshift 数据块。每个插入更新删除操作都会创建一组新的数据块,将旧数据块标记为逻辑删除。

有时,由于表交易的运行时间过长,逻辑删除在提交阶段无法清除。当同时运行的 ETL 负载太多时,逻辑删除也可能无法清除。由于 Amazon Redshift 从事务开始时就会监视数据库,因此写入数据库的任何表也会保留逻辑删除数据块。如果长期运行的表事务定期发生并跨多个负载,则会累积足够多的逻辑删除而导致磁盘已满错误。

您还可以通过执行提交命令强制 Amazon Redshift 执行关于逻辑删除数据块的分析。

如果有长期运行的查询处于活动状态,则使用提交命令终止查询(并释放所有后续数据块):

begin;
create table a (id int);
insert into a values(1);
commit;
drop table a;

然后,要确认逻辑删除数据块,请运行以下查询:

select trim(name) as tablename, count(case when tombstone > 0 then 1 else null end) as tombstones from svv_diskusage group by 1 having count(case when tombstone > 0 then 1 else null end) > 0 order by 2 desc;

复制大型文件

在 COPY 操作期间,即使有足够的可用存储空间,您也可能会收到磁盘已满错误。如果排序操作溢出到磁盘并创建临时数据块,则会发生此错误。

如果遇到磁盘已满错误信息,请检查 STL_DISK_FULL_DIAG 表。检查哪个查询 ID 引发错误以及创建的临时块:

select '2000-01-01'::timestamp + (currenttime/1000000.0)* interval '1 second' as currenttime,node_num,query_id,temp_blocks from pg_catalog.stl_disk_full_diag;

有关更多最佳实践,请参阅加载数据的 Amazon Redshift 最佳实践

其他问题排查方法

检查 Amazon Redshift 控制台中 **Performance(性能)**选项卡下方的磁盘空间百分比。对于每个集群节点,Amazon Redshift 会提供额外的磁盘空间,该空间大小大于标称磁盘容量。

如果您注意到利用率突然激增,请使用 STL_QUERY 以确定正在运行的活动和作业。注意磁盘溢出时正在运行哪些查询:

select * from stl_query where starttime between '2018-01-01 00:30:00' and '2018-01-01 00:40:00';

**注意:**使用发生峰值的时间更新值。

要确定前 20 个磁盘溢出查询,请运行以下查询:

select A.userid, A.query, blocks_to_disk, trim(B.querytxt) text from stl_query_metrics A, stl_query B where A.query = B.query and segment=-1 and step = -1 and max_blocks_to_disk > 0 order by 3 desc limit 20;

查看列值 blocks_to_disk 以识别磁盘溢出。如果需要,终止溢出过多的查询。然后,在再次运行查询之前,为它们分配额外的内存。有关更多详细信息,请参阅 STL_QUERY_METRICS

要确定您的查询是否正确写入磁盘,请运行以下查询:

SELECT q.query, trim(q.cat_text)
FROM (
SELECT query,
replace( listagg(text,' ') WITHIN GROUP (ORDER BY sequence), '\\n', ' ') AS cat_text
FROM stl_querytext
WHERE userid>1
GROUP BY query) q
JOIN (
SELECT distinct query
FROM svl_query_summary
WHERE is_diskbased='t' AND (LABEL ILIKE 'hash%' OR LABEL ILIKE 'sort%' OR LABEL ILIKE 'aggr%' OR LABEL ILIKE 'save%' OR LABEL ILIKE 'window%' OR LABEL ILIKE 'unique%')
AND userid > 1) qs
ON qs.query = q.query;

此命令还可识别溢出到磁盘的查询。


相关信息

Performance

Amazon Redshift 系统概述

AWS 官方
AWS 官方已更新 1 年前