匹配文本字段时非常慢的查询不是空字符串

时间:2013-02-24 23:30:11

标签: postgresql postgresql-9.1

我有一个非常简单的查询基本上是这样的:

Select * from my_table Where my_field != '';

表格中有大约40,000行,“my_field”列是文本字段(varchar 255)

查询大约需要39,000毫秒才能运行。我猜是因为它必须查看每个记录中的非空字符串。我已将my_field列编入索引,但它没有改变任何内容。

以防万一,这是查询计划:

"Seq Scan on my_table  (cost=0.00..3468.91 rows=39744 width=459)"
"  Filter: ((my_field)::text <> ''::text)"

这里最好的选择是什么?

解释分析:

"Seq Scan on my_table  (cost=0.00..3468.91 rows=39730 width=459) (actual time=0.021..13.763 rows=39714 loops=1)"
"  Filter: ((my_field)::text <> ''::text)"
"Total runtime: 14.856 ms"

我添加了这些索引

CREATE INDEX aa_idx ON my_table(my_field);
CREATE INDEX aa_idx ON my_table(my_field) WHERE my_field <> '';

这是Postgres 9.1

编辑:[2013-02-26 00:04GMT]

在“my_field”上创建分区作为检查约束会有什么好处吗?

类似CHECK(my_field ='')和分区2 CHECK(my_field!='')

我猜我的所有东西都是一张包含很多行的表格?但这是否意味着即使分区包含大约80%的数据,select!=''查询也会表现得更快?

我也研究过全文搜索,但这似乎是OTT。我还看了将列设为0或1(bool)的int,但这对性能没有影响(我猜是因为= 1仍会带回很多行?)

1 个答案:

答案 0 :(得分:2)

索引对你没用。我认为你需要找到一种更好的方法来巩固你的删除。

你说它需要39秒才能运行,但你提供的实际查询计划需要15毫秒才能运行,这大概是2000关。我无法想象一个缓存会对此有所帮助的情况,除非我们讨论的是具有大量TOASTed值的非常宽的表。这告诉我实际问题不在您的选择中,而在您的管道中的其他地方。这可能包括往返费用,但您正在进行删除。

我的建议是查看合并声明。这意味着避免往返,并尽可能多地将逻辑推送到单个查询中。由于您尚未发布完整的上下文,我建议您可以查看可写入的CTE,以便在不进行往返的情况下一起批量插入,更新和删除。