我一直觉得带有大WHERE x IN
子句的查询表现不佳。
例如,假设我有下表
psql> d examples
| Column | Type | Modifiers
| id | integer | not null default nextval('id_seq'::regclass)
| flag | boolean | not null
| date | timestamp | not null
| comment | character varying(16) | not null
Indexes:
"example_pkey" PRIMARY KEY, btree (id)
如果我使用具有 100k id 的 WHERE id IN
子句查询此表,它实际上返回相当快(表中有 100ks 行(:
EXPLAIN ANALYSE SELECT * FROM examples WHERE id IN (1, 2, ...., 100000);
Index Scan using examples_pkey on examples (cost=0.15..15012.60 rows=610 width=104) (actual time=18.380..18.380 rows=0 loops=1)
Index Cond: (id = ANY ('{1, 2, ... 100000}'::integer[]))
Planning time: 45.832 ms
Execution time: 42.708 ms
规划器已重写查询以将id = ANY
与我的 ID 列表一起使用,因此我认为这只是等效的,或者规划器知道这更快。
我以前有过其他查询,其中用子查询替换大WHERE IN
子句大大提高了查询速度。我在这里的查询非常简单,所以问题是:
具有大WHERE IN
子句的查询实际上表现不佳是真的吗?如果是这样,在哪种情况下是这种情况(假设列是索引等(。
分析器将列表中具有多个元素IN
表达式转换为=ANY
表达式。
如果列上有 B 树索引,则始终可以使用它。
我能想象到的唯一性能问题是优化程序可能会错误地估计结果行的数量,并在索引扫描实际上更快时选择顺序扫描。
实验表明,优化程序估计每个列表条目对唯一列的一个结果行,表中的行数最大。这是一个合理的估计值,但如果列表中有许多元素不匹配或存在重复项,则估计值很容易过高。