Postgres 性能:WHERE = Vs WHERE IN (...) for single values

Potsgres Performance: WHERE = Versus WHERE IN (...) for single values

我正在开发一个使用 Postgres 作为其后备数据库的应用程序。我正在开发一个在数据库上执行 SELECT 查询的组件,在 UI 上使用 multi-select 输入控件来提供查询的输入值。以前,这个输入控件是传统的 select 控件,因此一次只能指定一个选项。这意味着 SQL 查询看起来像这样:

SELECT * FROM items WHERE code = 'value1';

执行多 select 后,SQL 查询将如下所示:

SELECT * FROM items WHERE code IN ('value1', 'value2', 'value3');

但是,我有一个问题,关于用户何时只在 multi-select 中指定一个值。这意味着在括号内只指定一个值:

SELECT * FROM items WHERE code IN ('value1');

我发现此查询在语义上与使用 WHERE ... = ... 的查询相同。我的问题是两者之间是否存在显着的性能差异。我考虑过添加应用程序逻辑,如果只指定一个值,它会选择是否将 WHERE ... IN (...) 语句替换为其 WHERE ... = ... 对应语句?这个优化有必要吗?事实上,如果两种情况下的性能确实相同,那么当 WHERE ... IN (...) 更灵活时,为什么还要使用 WHERE ... = ... 呢?我是不是太担心微优化了?

谢谢。

SELECT * FROM items WHERE code = ('value1');(单值)

将以与

相同的方式处理

SELECT * FROM items WHERE code = 'value1';

SELECT * FROM items WHERE code IN ('value1');.

因此性能没有差异。使用 explain 检查这个。

TLDR:这没什么区别,性能始终相同,因此 IN 显然是您用例的赢家。

验证是否可以完成的快速测试:

test=# CREATE table test_in (id serial primary key);
CREATE TABLE
test=# explain select * from test_in where id = '1';
                                   QUERY PLAN
---------------------------------------------------------------------------------
 Index Only Scan using test_in_pkey on test_in  (cost=0.15..2.17 rows=1 width=4)
   Index Cond: (id = 1)
(2 rows)

test=# explain select * from test_in where id in ('1');
                                   QUERY PLAN
---------------------------------------------------------------------------------
 Index Only Scan using test_in_pkey on test_in  (cost=0.15..2.17 rows=1 width=4)
   Index Cond: (id = 1)
(2 rows)

注意方案是一样的,指标条件也是一样的,这样保证了同样的成本不是偶然的。在执行的查询重写阶段,PostgreSQL 检测到一些简单的等价情况,并以规范形式重写它们。

要查看另一个在语义上仍然等效但未重写为完全相同计划的查询示例,您可以尝试:

test=# explain select * from test_in where id in ('1', '1');
                                   QUERY PLAN
---------------------------------------------------------------------------------
 Index Only Scan using test_in_pkey on test_in  (cost=0.15..3.34 rows=2 width=4)
   Index Cond: (id = ANY ('{1,1}'::integer[]))
(2 rows)