如何排除 Amazon Redshift 占用大量磁盘空间或用尽磁盘空间的问题?
我遇到了 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;
此命令还可识别溢出到磁盘的查询。
相关信息
相关内容
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前