【发布时间】:2015-06-29 15:36:49
【问题描述】:
我有一个表users,索引在id。
我有另一个表 orders 属于 users 并且有一个 user_id 字段也被索引
我有以下疑问:
SELECT * FROM users
WHERE id IN (
SELECT user_id FROM orders
WHERE user_id = '4CF93940-390D-4D70-BE62-61AFC73663BF'
);
这里 Postgres 正确使用了这两个索引(通过检查 EXPLAIN 的输出)。
但是,如果我这样做:
SELECT * FROM users
WHERE id IN (
SELECT user_id FROM orders
);
(从内部 Select 中移除 where 子句)
它根本不使用任何索引。它不使用orders.user_id 上的索引,因为我选择了所有它,但是为什么它不使用users.id 上的索引呢?
这是两个查询的解释输出:
Nested Loop Semi Join (cost=4.36..22.54 rows=1 width=16)
-> Index Only Scan using user_id on users (cost=0.15..8.17 rows=1 width=16)
Index Cond: (id = '4cf93940-390d-4d70-be62-61afc73663bf'::uuid)
-> Bitmap Heap Scan on orders (cost=4.21..14.35 rows=7 width=16)
Recheck Cond: (user_id = '4cf93940-390d-4d70-be62-61afc73663bf'::uuid)
-> Bitmap Index Scan on order_user_id (cost=0.00..4.21 rows=7 width=0)
Index Cond: (user_id = '4cf93940-390d-4d70-be62-61afc73663bf'::uuid)
Hash Join (cost=30.88..67.21 rows=885 width=16)
Hash Cond: (users.id = orders.user_id)
-> Seq Scan on users (cost=0.00..27.70 rows=1770 width=16)
-> Hash (cost=28.38..28.38 rows=200 width=16)
-> HashAggregate (cost=26.38..28.38 rows=200 width=16)
Group Key: orders.user_id
-> Seq Scan on orders (cost=0.00..23.10 rows=1310 width=16)
更新:
所以运行这个查询:
EXPLAIN SELECT * FROM users
WHERE id IN ('4CF93940-390D-4D70-BE62-61AFC73663BF', '4CF93940-390D-4D70-BE62-61AFC73663BF');
正确使用索引。所以基本上为什么是
WHERE id IN ('4CF93940-390D-4D70-BE62-61AFC73663BF', '4CF93940-390D-4D70-BE62-61AFC73663BF')
不同于
WHERE id IN (SELECT user_id FROM orders);
似乎两者都只是一个 id 数组。
【问题讨论】:
-
它不使用索引,因为当从表
orders返回所有行(或大部分行)时,seq 扫描效率更高。在第二个示例中,Postgres 期望返回 1310 行中的 885 行。 -
@a_horse_with_no_name 是的,我明白为什么它不使用
orders的索引,但是一旦它有一个数组(或集合)或user_ids 为什么不使用@987654338 上的索引@找到所有用户? -
正如我所说:因为如果需要检索表中的大部分行,使用 seq 扫描会更有效。索引扫描每行需要比 seq 扫描更多的随机 I/O。按索引查找行需要搜索叶节点的索引(1-3 次 I/O 操作),然后进行另一个 I/O 操作来检索表的行。如果你重复很多很多次,它会变得非常慢。另一方面,seq 扫描通过单个 I/O 操作检索多行 - 如果您需要的不仅仅是几行,效率会更高
-
@a_horse_with_no_name 感谢您的回复。是的,我知道在获取表的大部分内容时,seq 扫描效率更高。但是,1)这些是我现在创建的玩具表(以隐藏我的表的复杂性),它们没有任何内容,因此在 2 种情况下应该没有什么不同(请参阅我的更新)。 2)我将我的 id 列从 UUID 更改为整数,现在它按预期两次使用索引。似乎是 UUID 上的索引有问题。
标签: database postgresql indexing