表的维护:在截断和重新填充后是否需要重新索引表?

Jam*_*esF 8 postgresql database database-performance

我有一个包含大约 200 万行交易数据的表,用于分析。每周我们都会用新数据重新加载它,因此我们一直使用 TRUNCATE 将其清除,然后插入新行。

表上有几个索引。如果我不删除并重新创建索引,我是否需要在每次截断和重新填充后重新编制索引,还是没有必要?我应该在 TRUNCATE 之后运行 VACUUM 还是这也是不必要的?

Cra*_*ger 5

不,您通常不需要在之后重新建立索引TRUNCATE- 如果需要,最好删除索引,加载数据,然后在最后重新创建索引。

这有点类似于关于集群的答案- Pg 在插入数据期间自动删除索引TRUNCATE,然后在插入数据时增量重建索引,因此在TRUNCATE.

如果删除索引、截断、插入数据并重新创建索引,您可能会获得更紧凑、更高效的索引。它们的构建速度肯定会更快。对于大多数仅使用 B 树索引的应用程序来说,一旦建立索引性能的差异就不太可能足以保证付出额外的努力,但填充表所需的时间差异可能是值得的。如果您使用 GiST 或(尤其是)GIN,最好删除索引并在最后重新创建。

如果这样做方便的话,可以删除索引并在最后将它们添加回来,如果这对您来说不实用,请不要太担心。

对于我测试中的常规 B 树,增量创建的复合索引为 3720kb,而一次性创建的索引为 2208kb。构建时间为 164 毫秒(插入)+ 347 毫秒(索引)与 742 毫秒(插入+索引)。这种差异很显着,但还不足以成为一个巨大的问题,除非您正在进行大规模 DW。REINDEX在插入+索引运行后,A又花费了 342 毫秒。看

因此,@TomTom 是对的(毫不奇怪),因为如果方便的话,值得删除并重新创建索引,就像您为 OLAP 工作批量填充表一样。

然而,重新索引可能是错误的答案,因为这意味着您需要做大量昂贵的工作来创建索引,然后将其丢弃。删除索引并重新创建它而不是重新索引。

演示会议:

regress=# -- Create, populate, then create indexes:
regress=# CREATE TABLE demo (someint integer, sometext text);
CREATE TABLE
regress=# \timing on
regress=# INSERT INTO demo (someint, sometext)
SELECT x, (x%100)::text
FROM generate_series(1,100000) x;
INSERT 0 100000
Time: 164.678 ms
regress=# CREATE INDEX composite_idx ON demo(sometext, someint);
CREATE INDEX
Time: 347.958 ms
regress=# SELECT pg_size_pretty(pg_indexes_size('demo'::regclass));
 pg_size_pretty 
----------------
 2208 kB
(1 row)
regress=# -- Total time: 347.958+164.678=512.636ms, index size 2208kB

regress=# -- Now, with truncate and insert:
regress=# TRUNCATE TABLE demo;
TRUNCATE TABLE
regress=# INSERT INTO demo (someint, sometext)
SELECT x, (x%100)::text
FROM generate_series(1,100000) x;
INSERT 0 100000
Time: 742.813 ms
regress=# SELECT pg_size_pretty(pg_indexes_size('demo'::regclass));
 pg_size_pretty 
----------------
 3720 kB
(1 row)
regress=# -- Total time 742ms, index size 3720kB
regress=# -- Difference: about 44% time increase, about 68% index size increase.
regress=# -- Big-ish, but whether you care depends on your application. Now:

regress=# REINDEX INDEX composite_idx ;
REINDEX
Time: 342.283 ms
regress=# SELECT pg_size_pretty(pg_indexes_size('demo'::regclass));
 pg_size_pretty 
----------------
 2208 kB
(1 row)

regress=# -- Index is back to same size, but total time for insert with progressive
regress=# -- index build plus reindex at the end us up to 1084.283, twice as long as
regress=# -- dropping the indexes, inserting the data, and re-creating the indexes took.
Run Code Online (Sandbox Code Playgroud)

所以:

  • 对于 OLAP,删除索引、插入、重新创建索引。

  • 对于 OLTP,您可能只想坚持使用渐进式索引构建。考虑对索引使用非 100% 填充因子以降低插入成本。

  • 避免使用渐进索引构建插入然后重新索引,这是两全其美的情况。

当然,此测试中使用的大小是玩具表大小,因此您应该对现实世界数据和索引的样本重复此测试,以充分了解它对有多大影响。我使用比上面大 100 的比例因子重复这些测试,并且始终发现,如果增量构建,索引的大小几乎恰好是两倍,尽管相对构建时间差异实际上在这个特定测试中有所下降。

所以:用你的数据和模式进行测试。