我使用SQL运行EXPLAIN命令并获得计划。
explain analyze SELECT "users2_device2"."id", "users2_device2"."device_token", "users2_device2"."os_type"
FROM "users2_device2"
WHERE (
"users2_device2"."user_id" IN (
SELECT V0."user_id"
FROM "users2_pushsetting2" V0
WHERE (V0."user_id" IN (
SELECT U0."from_user_id"
FROM "users2_followingusers" U0
WHERE (
U0."to_user_id" = 1700019
AND U0."favorite" = true
)
) AND V0."live" = true)
) AND "users2_device2"."status" = 0
);
。
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| QUERY PLAN |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Hash Semi Join (cost=36089.60..70812.80 rows=99600 width=6) (actual time=1306.602..1601.587 rows=100000 loops=1) |
| Output: users2_device2.id, users2_device2.device_token, users2_device2.os_type |
| Hash Cond: (users2_device2.user_id = v0.user_id) |
| -> Seq Scan on public.users2_device2 (cost=0.00..20834.12 rows=1000010 width=10) (actual time=0.006..382.735 rows=1000010 loops=1) |
| Output: users2_device2.id, users2_device2.device_token, users2_device2.os_type, users2_device2.user_id |
| Filter: (users2_device2.status = 0) |
| -> Hash (cost=34454.60..34454.60 rows=99600 width=8) (actual time=803.194..803.194 rows=100000 loops=1) |
| Output: v0.user_id, u0.from_user_id |
| Buckets: 131072 Batches: 2 Memory Usage: 2984kB |
| -> Hash Semi Join (cost=5163.43..34454.60 rows=99600 width=8) (actual time=504.350..769.445 rows=100000 loops=1) |
| Output: v0.user_id, u0.from_user_id |
| Hash Cond: (v0.user_id = u0.from_user_id) |
| -> Seq Scan on public.users2_pushsetting2 v0 (cost=0.00..17354.10 rows=1000010 width=4) (actual time=0.002..318.386 rows=1000010 loops=1) |
| Output: v0.user_id |
| Filter: v0.live |
| -> Hash (cost=3528.43..3528.43 rows=99600 width=4) (actual time=62.920..62.920 rows=100000 loops=1) |
| Output: u0.from_user_id |
| Buckets: 131072 Batches: 2 Memory Usage: 2788kB |
| -> Index Only Scan using users2_followingusers_to_user_id_favorite_from_ba2688fe_uniq on public.users2_followingusers u0 (cost=0.42..3528.43 rows=99600 width=4) (actual time=0.011..30.535 rows=100000 loops=1) |
| Output: u0.from_user_id |
| Index Cond: ((u0.to_user_id = 1700019) AND (u0.favorite = true)) |
| Filter: u0.favorite |
| Heap Fetches: 0 |
| Planning time: 0.420 ms |
| Execution time: 1621.003 ms |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
记下Seq Scan on public.users2_pushsetting2
。
我认为,如果我为(live, user_id)
添加索引,它将通过仅索引扫描来加快速度。
但是,尽管它使用仅索引扫描,但是它可以降低教育状况。
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| QUERY PLAN
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Nested Loop Semi Join (cost=0.90..64437.19 rows=99589 width=6) (actual time=3127.140..4772.221 rows=100000 loops=1)
| -> Seq Scan on users2_device2 (cost=0.00..20833.25 rows=999940 width=10) (actual time=0.007..383.861 rows=1000010 loops=1)
| Filter: (status = 0)
| -> Hash Semi Join (cost=0.90..0.93 rows=1 width=8) (actual time=0.004..0.004 rows=0 loops=1000010)
| Hash Cond: (v0.user_id = u0.from_user_id)
| -> Index Only Scan using users2_pushsetting2_user_id_live_e89f5671_uniq on users2_pushsetting2 v0 (cost=0.42..0.46 rows=1 width=4) (actual time=0.001..0.001 rows=1 loops=100
| Index Cond: ((user_id = users2_device2.user_id) AND (live = true))
| Filter: live
| Heap Fetches: 0
| -> Hash (cost=0.46..0.46 rows=1 width=4) (actual time=0.002..0.002 rows=0 loops=1000010)
| Buckets: 1024 Batches: 1 Memory Usage: 8kB
| -> Index Only Scan using users2_followingusers_to_user_id_favorite_from_ba2688fe_uniq on users2_followingusers u0 (cost=0.42..0.46 rows=1 width=4) (actual time=0.002..
| Index Cond: ((to_user_id = 1700019) AND (favorite = true) AND (from_user_id = users2_device2.user_id))
| Filter: favorite
| Heap Fetches: 0
| Planning time: 0.459 ms
| Execution time: 4793.639 ms
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
看起来是因为(from_user_id = users2_device2.user_id)
条件被移到了根节点,并且Hash Semi Join
被删除了。(Optimizer Flats条件)
因此,我尝试通过添加如下所示的`OFFSET 0来使Optimizer不处于平坦状态。
explain analyze SELECT "users2_device2"."id", "users2_device2"."device_token", "users2_device2"."os_type"
FROM "users2_device2"
WHERE (
"users2_device2"."user_id" IN (
SELECT V0."user_id"
FROM "users2_pushsetting2" V0
WHERE (V0."user_id" IN (
SELECT U0."from_user_id"
FROM "users2_followingusers" U0
WHERE (
U0."to_user_id" = 1700019
AND U0."favorite" = true
) OFFSET 0
) AND V0."live" = true)
) AND "users2_device2"."status" = 0
);
但是,它返回到不使用仅索引扫描的第一个计划。
我想念什么?