使用 IN 和列表进行 SQL 查询非常慢

tup*_*pan 1 sql postgresql

有没有办法优化这样的查询:

SELECT count(*) FROM mytable 
WHERE 
indexed_field IN ('v1', 'v2', ..., 'v2000')
AND NOT regular_field='something'
AND other_regular_field='something_else';
Run Code Online (Sandbox Code Playgroud)

这个查询“有效”。问题是它非常慢(1分钟以上)。我认为使用IN定义的列表来使用表达式就可以了,但事实证明并不是那么好。

我正在使用 Postgresql 9.6。

我的表有310K。

查询解释:

QUERY PLAN
Aggregate  (cost=396158.70..396158.71 rows=1 width=8) (actual time=8630.558..8630.559 rows=1 loops=1)
  ->  Seq Scan on mytable  (cost=0.00..396156.77 rows=772 width=0) (actual time=7853.840..8630.478 rows=916 loops=1)
        Filter: (((non_indexed_field)::text <> 'value1'::text) AND ((non_indexed_field)::text = 'value2'::text) AND ((indexed_field)::text = ANY ('{lots and lots of values....}'::text[])))
        Rows Removed by Filter: 306768
Planning time: 2.543 ms

Execution time: 8630.770 ms
Run Code Online (Sandbox Code Playgroud)

通过分析、缓冲:

Aggregate  (cost=396158.70..396158.71 rows=1 width=8) (actual time=9278.560..9278.560 rows=1 loops=1)
   Buffers: shared hit=14244
   ->  Seq Scan on mytable  (cost=0.00..396156.77 rows=772 width=0) (actual time=8584.520..9278.431 rows=916 loops=1)
         Filter: (((non_indexed_field)::text <> 'value1'::text) AND ((non_indexed_field)::text = 'value2'::text) AND ((indexed_field)::text = ANY ('{lots and lots of values}'::text[])))
         Rows Removed by Filter: 306768
         Buffers: shared hit=14244
 Planning time: 1.293 ms
 Execution time: 9278.646 ms
(8 rows)
Run Code Online (Sandbox Code Playgroud)

小智 7

很多时候加入 aaVALUES子句会更有效:

SELECT count(*) 
FROM mytable 
  JOIN (
     values ('v1'), ('v2'), (...), ('v2000')
  ) as lookup(value) on lookup.value = mytable.some_column
WHERE NOT other_column = 'something'
AND another_column = 'something_else';
Run Code Online (Sandbox Code Playgroud)

注意“列表”的格式。在values子句中,每个值都需要括在括号中。('v1'), ('v2'), ...代替('v1', 'v2', ...)

在线示例: http: //rextester.com/UUWVG71217


请注意,如果与值进行比较的列确实是数字(例如整数),则不应使用单引号指定值,例如values (1),(2),(3),...(2000)