我有这个非常简单的查询,由我的 ORM(实体框架核心)生成:
SELECT *
FROM "table1" AS "t1"
WHERE EXISTS (
SELECT 1
FROM "table2" AS "t2"
WHERE ("t2"."is_active" = TRUE) AND ("t1"."table2_id" = "t2"."id"))
ORDER BY "t1"."table2_id"
- 有 2 个“is_active”记录。其他涉及的列(“id”)是主键。查询正好返回 4 行。
- 表 1 是 9600 万条记录。
- 表 2 是 3000 万条记录。
- 此查询中涉及的 3 列已编入索引(is_active、id、table2_id)。
- 生成这个简单查询的 C#/LINQ 代码是:Table2.Where(t => t.IsActive).Include(t => t.Table1).ToList();`
SET STATISTICS 10000
设置为所有 3 列。VACUUM FULL ANALYZE
在两张桌子上运行。
如果没有该ORDER BY
子句,查询会在几毫秒内返回,我不希望返回 4 条记录。解释输出:
Nested Loop (cost=1.13..13.42 rows=103961024 width=121)
-> Index Scan using table2_is_active_idx on table2 (cost=0.56..4.58 rows=1 width=8)
Index Cond: (is_active = true)
Filter: is_active
-> Index Scan using table1_table2_id_fkey on table1 t1 (cost=0.57..8.74 rows=10 width=121)
Index Cond: (table2_id = table1.id)
WITHORDER BY
子句,查询需要5分钟完成!解释输出:
Merge Semi Join (cost=10.95..4822984.67 rows=103961040 width=121)
Merge Cond: (t1.table2_id = t2.id)
-> Index Scan using table1_table2_id_fkey on table1 t1 (cost=0.57..4563070.61 rows=103961040 width=121)
-> Sort (cost=4.59..4.59 rows=2 width=8)
Sort Key: t2.id
-> Index Scan using table2_is_active_idx on table2 a (cost=0.56..4.58 rows=2 width=8)
Index Cond: (is_active = true)
Filter: is_active
内部的第一个索引扫描应返回不超过 2 行。然后外部的第二个索引扫描没有任何意义,因为它的成本为 4563070 和 103961040 行。它只需要匹配 2 行table2
和 4 行table1
!
这是一个非常简单的查询,返回的记录很少。为什么 Postgres 无法正确执行它?