不同的结果取决于我在插入数据之前还是之后创建GIN索引的时间

时间:2019-11-10 05:11:55

标签: postgresql

我试图用GIN构建一个非常简单的文本数组_text_ops。我了解ts_vectors的全部知识-出于好奇,我只想使用文本数组来完成此操作,而我在PostgreSQL 9.6中看到了一种奇怪的行为。这是我的命令序列:

drop table docs cascade;
drop index gin1;
CREATE TABLE docs (id SERIAL, doc TEXT, PRIMARY KEY(id));
-- create index gin1 on docs using gin(string_to_array(doc, ' ')  _text_ops);  -- before
INSERT INTO docs (doc) VALUES
('This is SQL and Python and other fun teaching stuff'),
('More people should learn SQL from us'),
('We also teach Python and also SQL');
SELECT * FROM docs;
create index gin1 on docs using gin(string_to_array(doc, ' ')  _text_ops);  -- after
explain select doc from docs where '{SQL}' <@ string_to_array(doc, ' ');

如果我在插入之前创建gin1索引,则explain会按预期工作:

pg4e=> explain select doc FROM docs WHERE '{SQL}' <@ string_to_array(doc, ' ');
 Bitmap Heap Scan on docs  (cost=12.05..21.53 rows=6 width=32)
   Recheck Cond: ('{SQL}'::text[] <@ string_to_array(doc, ' '::text))
   ->  Bitmap Index Scan on gin1  (cost=0.00..12.05 rows=6 width=0)
         Index Cond: ('{SQL}'::text[] <@ string_to_array(doc, ' '::text))

如果我在插入后创建gin索引,它似乎永远不会使用该索引。

pg4e=> explain select doc from docs where '{SQL}' <@ string_to_array(doc, ' ');
 Seq Scan on docs  (cost=0.00..1.04 rows=1 width=32)
   Filter: ('{SQL}'::text[] <@ string_to_array(doc, ' '::text))

我想知道是否是因为我需要等待一段时间才能完全填充索引(即使有四行)-但是等待几分钟并执行explain仍然可以给我进行顺序表扫描。 / p>

然后只是为了好玩我再插入10000条记录

INSERT INTO docs (doc) SELECT 'Neon ' || generate_series(10000,20000);

explain会显示大约10秒钟的Seq扫描,然后在10秒钟后如果我再执行一次explain,则会显示位图堆扫描。显然,一些索引更新花了一些时间-这很有意义。但是在第一种情况下,我先插入四行然后创建索引-不管我等待explain多长时间,都永远不会使用索引。

我有一个解决方法(在执行插入操作之前先创建索引)-我只是想知道是否存在某种机制,例如“刷新索引”或我错过了这种机制-或其他某种机制在起作用。

1 个答案:

答案 0 :(得分:0)

  

说明显示Seq扫描大约10秒,然后10秒后   秒,如果我再做一次说明,则显示位图堆扫描。所以   显然,一些索引更新花了一些时间-这使得   感。但是在第一种情况下,我插入四行,然后   创建索引-无论我等待多长时间,解释都不会使用   索引。

在4行表中插入10,000行时,您超出了autovacuum_analyze_threshold和autovacuum_analyze_scale_factor确定的活动级别。因此,下次自动清理启动器访问您的数据库时,它将执行该表的ANALYZE,并使用该ANALYZE上的新数据在较大的表上确定索引扫描将很有用。但是,如果仅插入4行,则不会触发自动分析(autovacuum_analyze_threshold的默认值为50)。如果确实如此,则ANALYZE的结果将是表太小以至于索引无用,因此计划也不会改变。

  

我有一个解决方法(在执行插入操作之前先建立索引)

要解决该问题,您需要解决一个问题。您似乎在这里没有真正的问题(无论如何,持续时间比autovacuum_naptime更长),因此没有任何解决方法。