在 Postgres 9.6 中,在具有大约 1200 万行的用户表中,active
bool 列上有一个 btree 索引。
EXPLAIN ANALYZE SELECT * FROM users WHERE active = 'f' LIMIT 1;
Limit (cost=0.00..0.14 rows=1 width=982) (actual time=0.039..0.040 rows=1 loops=1)
-> Seq Scan on users (cost=0.00..3190979.68 rows=23264168 width=982) (actual time=0.036..0.036 rows=1 loops=1)
Filter: (NOT active)
Rows Removed by Filter: 115
Planning time: 0.161 ms
Execution time: 0.067 ms
但是,使用 IS FALSE
似乎使用了索引。
EXPLAIN ANALYZE SELECT * FROM users WHERE active IS FALSE LIMIT 1;
Limit (cost=0.44..0.59 rows=1 width=982) (actual time=0.054..0.056 rows=1 loops=1)
-> Index Scan using index_users_on_active on users (cost=0.44..2059.14 rows=13183 width=982) (actual time=0.051..0.051 rows=1 loops=1)
Index Cond: (active = false)
Filter: (active IS FALSE)
Planning time: 0.170 ms
Execution time: 0.094 ms
绝大多数记录的事件值为 true
,而且我知道索引并不总是更快。
Rails 似乎更喜欢 active = 'f'
语法,因为这是它在构建查询时输出的内容。
为什么这些不同?它们有何不同?应该使用另一个吗?
最佳答案
区别在于 NULL 值的处理方式。根据 docs :
IS FALSE
将始终返回 bool 值,即使参数为 null。= 'f'
如果参数为 null,则返回 null。
为了说明,
rnubel=# SELECT NULL = 'f' as equals_false, NULL IS FALSE as is_false;
equals_false | is_false
--------------+----------
| f
通常,SQL 中的大多数事物都将在三元逻辑基础上运行,其中空值产生空结果;因此,Rails 默认使用与该基础一致的运算符也就不足为奇了。但是,它与您在 Ruby 中的预期不同(其中 !nil == true
),因此它可能是许多意外行为的原因。
关于sql - IS FALSE 和 = 'f' 在 Postgres 和索引使用中的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46410610/