Gre*_*reg 7 postgresql index database-design database-recommendation partitioning
我有超过 10 年的时间序列数据,有超过 3 万亿行和 10 列。
目前我使用具有 128GB RAM 的 PCIe SSD,我发现查询需要大量时间。例如,运行以下命令需要超过 15 分钟:
SELECT * FROM tbl WHERE column_a = 'value1' AND column_b = 'value2';
Run Code Online (Sandbox Code Playgroud)
该表主要用于读取。写入表的唯一时间是在每周更新期间插入大约 1500 万行。
管理如此大的表的最佳方法是什么?您会建议按年份拆分吗?
表大小为 542 GB,外部大小为 109 GB。
EXPLAIN (BUFFERS, ANALYZE) 输出:
"Seq Scan on table (cost=0.00..116820941.44 rows=758 width=92) (actual time=0.011..1100643.844 rows=667 loops=1)"
" Filter: (("COLUMN_A" = 'Value1'::text) AND ("COLUMN_B" = 'Value2'::text))"
" Rows Removed by Filter: 4121893840"
" Buffers: shared hit=2 read=56640470 dirtied=476248 written=476216"
"Total runtime: 1100643.967 ms"
Run Code Online (Sandbox Code Playgroud)
该表是使用以下代码创建的:
CREATE TABLE tbl (
DATE timestamp with time zone,
COLUMN_A text,
COLUMN_B text,
VALUE_1 double precision,
VALUE_2 double precision,
VALUE_3 double precision,
VALUE_4 double precision,
VALUE_5 double precision,
VALUE_6 double precision,
VALUE_7 double precision,
);
CREATE INDEX ix_table_name_date ON table_name (DATE);
Run Code Online (Sandbox Code Playgroud)
您现有的索引DATE显然对查询无用。查询的第一个明显步骤:
SELECT * FROM tbl WHERE column_a = 'value1' AND column_b = 'value2';
Run Code Online (Sandbox Code Playgroud)
是索引为column_a或column_b(其中曾经是更具选择性的),或者可能在多列索引(column_a, column_b),如:
CREATE INDEX tbl_a_b_idx ON tbl(column_a, column_b);
Run Code Online (Sandbox Code Playgroud)
细节:
接下来,如果您可以安全地从查询中排除表的大部分内容,我将考虑部分索引。或者将您的表划分为 100 个分区。并使用约束排除。
正如您所设想的那样,“按年份拆分”将DATE与给定查询的索引一样无用(甚至有害)。分区需要基于查询谓词 (column_a和column_b) 中的列才能有所帮助。在这方面,仅一列上的谓词会容易得多。如果您对各个列有重要的查询过滤,分区可能不是要走的路。(部分索引仍然可能。)
如果分区不好,那么侵入性较小的措施是CLUSTER基于新索引的数据(您不能为此使用部分索引)。或者简单地从查询的排序输出创建一个新表。这特别有趣,因为您的表大多是只读的。应该支付至少这样做一次,但是这一次将是非常昂贵的:整个表必须重新编写一个或其他方式。您需要足够的可用空间、尽可能多的 RAM 以及对表的独占锁。或者使用pg_repack, 避免排他锁:
确保运行最新版本的 Postgres。即将发布的Postgres 9.5对您来说可能特别有趣,因为它引入了BRIN 索引(块范围索引),它可以显着减少非常大的表的索引大小。可能正是您正在寻找的。
| 归档时间: |
|
| 查看次数: |
2102 次 |
| 最近记录: |