Redshift的设计是Blocks are immutable。当进行更新操作时,会写到新的block上面;当删除行时,记录并没有从磁盘上移除,只是做了个删除标记,被删除的行依然占用磁盘空间,当进行查询时依然会被扫描到。所以,这会造成磁盘空间的浪费和查询性能的降低。
DELETE 操作:
┌─────────────────────┐
│ Row 1 ✓ 有效 │
│ Row 2 ✗ 标记删除 │ ← 只是打标记,空间没释放
│ Row 3 ✓ 有效 │
│ Row 4 ✗ 标记删除 │
│ Row 5 ✓ 有效 │
└─────────────────────┘
UPDATE 操作 = DELETE + INSERT:
原行标记删除 + 末尾插入新行
Redshift可以在后台自动执行 VACUUM操作,VACCUUM命令可以恢复空间、重新进行table sort。
当系统空闲时,Redshift会自动在后台执行VACUUM;而当系统负载过高时,会暂停操作。当表进行vacuum操作时,用户依然可以进行查询操作。
最佳实践是尽可能频繁的进行VACUUM操作,以提高查询性能。当系统负载不高(例如深夜时),或者维护窗口期,可以进行vacuum操作。
VACUUM FULL table_name;
| 操作 | 是否执行 |
|---|---|
| 回收空间 | ✅ |
| 重新排序 | ✅ |
| 最彻底 | ✅ |
| 耗时 | 最长 |
VACUUM DELETE ONLY table_name;
| 操作 | 是否执行 |
|---|---|
| 回收空间 | ✅ |
| 重新排序 | ❌ |
| 适用场景 | 只做了 DELETE,没有 INSERT |
VACUUM SORT ONLY table_name;
| 操作 | 是否执行 |
|---|---|
| 回收空间 | ❌ |
| 重新排序 | ✅ |
| 适用场景 | 只做了 INSERT,没有 DELETE |
VACUUM REINDEX table_name;
| 操作 | 是否执行 |
|---|---|
| 回收空间 | ✅ |
| 重新排序 | ✅ |
| 重建 Interleaved 索引 | ✅ |
| 适用场景 | Interleaved Sort Key 表专用 |
类型对比:
| VACUUM 类型 | 回收空间 | 排序 | 重建 Interleaved | 耗时 |
|---|---|---|---|---|
| FULL | ✅ | ✅ | ❌ | 长 |
| DELETE ONLY | ✅ | ❌ | ❌ | 短 |
| SORT ONLY | ❌ | ✅ | ❌ | 中 |
| REINDEX | ✅ | ✅ | ✅ | 最长 |
-- 使用全部资源加速 VACUUM(独占模式)
VACUUM BOOST table_name;
执行VACCUM的一些最佳实践:
| 场景 | 推荐操作 |
|---|---|
| 大量 DELETE 后 | VACUUM DELETE ONLY |
| 大量 INSERT 后 | VACUUM SORT ONLY |
| 日常维护 | VACUUM FULL(或依赖自动) |
| Interleaved 表维护 | VACUUM REINDEX(必须手动) |
| 大表 | 分批或在维护窗口执行 |
svv_vacuum_progress表,可以查看VACUUM的进度BOOST模式,该模式下会给VACCUM命令分配更多的内存/磁盘资源,加快进度。但执行的时候会阻拦delete/update操作。在大表上进行vaccum操作速度非常慢。当表大于700GB时,可以考虑使用deep copy:
deep copy示例:
create table partscopy(
ps_partkey bigint not null,
ps_suppkey integer not null,
ps_availqty integer not null
) diststyle even;
insert into public.partscopy( select * from parts);
drop table parts;
alter table partscopy rename to parts;
第二种方式:
create table public.partscopy (like public.parts);
insert into public.partscopy (select * from parts);
drop table parts;
alter talbe partscopy rename to parts;