=> EXPLAIN SELECT *
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
WHERE t.ticket_no = '0005432000284';
QUERY PLAN
----------------------------------------------------------------
Nested Loop (cost=0.99..25.05 rows=3 width=136)
-> Index Scan using tickets_pkey on tickets t
(cost=0.43..8.45 rows=1 width=104)
Index Cond: (ticket_no = '0005432000284'::bpchar)
-> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.57 rows=3 width=32)
Index Cond: (ticket_no = '0005432000284'::bpchar)
(7 rows)
QUERY PLAN
----------------------------------------------------------------
Nested Loop (cost=0.99..25.05 rows=3 width=136)
-> Index Scan using tickets_pkey on tickets t
(cost=0.43..8.45 rows=1 width=104)
× 1
Index Cond: (ticket_no = '0005432000284'::bpchar)
-> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.57 rows=3 width=32)
Index Cond: (ticket_no = '0005432000284'::bpchar)
(7 rows)
=> CREATE INDEX ON tickets(book_ref);
=> EXPLAIN SELECT *
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
WHERE t.book_ref = '03A76D';
QUERY PLAN
----------------------------------------------------------------
Nested Loop (cost=0.99..45.67 rows=6 width=136)
-> Index Scan using tickets_book_ref_idx on tickets t
(cost=0.43..12.46 rows=2 width=104)
Index Cond: (book_ref = '03A76D'::bpchar)
-> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..16.57 rows=3 width=32)
Index Cond: (ticket_no = t.ticket_no)
(7 rows)
=> EXPLAIN (analyze, costs off, timing off, summary off, buffers off)
SELECT * FROM flights f
JOIN aircrafts_data a ON f.aircraft_code = a.aircraft_code
WHERE f.flight_no = 'PG0003';
QUERY PLAN
---------------------------------------------------------------------
Nested Loop (actual rows=113.00 loops=1)
-> Bitmap Heap Scan on flights f
(actual rows=113.00 loops=1)
Recheck Cond: (flight_no = 'PG0003'::bpchar)
Heap Blocks: exact=2
-> Bitmap Index Scan on flights_flight_no_scheduled_depart...
(actual rows=113.00 loops=1)
Index Cond: (flight_no = 'PG0003'::bpchar)
Index Searches: 1
-> Memoize (actual rows=1.00 loops=113)
Cache Key: f.aircraft_code
Cache Mode: logical
Hits: 112 Misses: 1 Evictions: 0 Overflows: 0 Memory
Usage: 1kB
-> Index Scan using aircrafts_pkey on aircrafts_data a
(actual rows=1.00 loops=1)
Index Cond: (aircraft_code = f.aircraft_code)
Index Searches: 1
(18 rows)
外连接
嵌套循环连接可用于 左外连接(节点 Nested Loop Left Join)。在此示例中,规划器选择了非参数化连接:
=> EXPLAIN SELECT * FROM ticket_flights tf
LEFT JOIN boarding_passes bp ON bp.ticket_no = tf.ticket_no
AND bp.flight_id = tf.flight_id
WHERE tf.ticket_no = '0005434026720' and tf.flight_id = 82977;
QUERY PLAN
---------------------------------------------------------------------
Nested Loop Left Join (cost=1.12..17.17 rows=1 width=57)
-> Index Scan using ticket_flights_pkey on ticket_flights tf
(cost=0.56..8.58 rows=1 width=32)
Index Cond: ((ticket_no = '0005434026720'::bpchar) AND (fl...
-> Index Scan using boarding_passes_pkey on boarding_passes bp
(cost=0.56..8.58 rows=1 width=25)
Index Cond: ((ticket_no = '0005434026720'::bpchar) AND (fl...
(7 rows)
反连接可用于计算 NOT EXISTS 谓词。例如,找出尚未配置客舱布局的飞机型号。嵌套循环反连接在计划中由节点 Nested Loop Anti Join 表示:
=> EXPLAIN SELECT *
FROM aircrafts a
WHERE NOT EXISTS (
SELECT * FROM seats s WHERE s.aircraft_code = a.aircraft_code
);
QUERY PLAN
---------------------------------------------------------------------
Nested Loop Anti Join (cost=0.28..5.26 rows=1 width=40)
-> Seq Scan on aircrafts_data ml (cost=0.00..1.09 rows=9 widt...
-> Index Only Scan using seats_pkey on seats s
(cost=0.28..10.64 rows=149 width=4)
Index Cond: (aircraft_code = ml.aircraft_code)
(5 rows)
对于等价的无 NOT EXISTS 查询,也将生成相同的计划:
=> EXPLAIN SELECT a.*
FROM aircrafts a
LEFT JOIN seats s ON a.aircraft_code = s.aircraft_code
WHERE s.aircraft_code IS NULL;
QUERY PLAN
---------------------------------------------------------------------
Nested Loop Anti Join (cost=0.28..5.26 rows=1 width=40)
-> Seq Scan on aircrafts_data ml (cost=0.00..1.09 rows=9 widt...
-> Index Only Scan using seats_pkey on seats s
(cost=0.28..10.64 rows=149 width=4)
Index Cond: (aircraft_code = ml.aircraft_code)
(5 rows)
=> EXPLAIN SELECT *
FROM aircrafts a
WHERE EXISTS (
SELECT * FROM seats s WHERE s.aircraft_code = a.aircraft_code
);
QUERY PLAN
---------------------------------------------------------------------
Nested Loop Semi Join (cost=0.28..7.28 rows=9 width=40)
-> Seq Scan on aircrafts_data ml (cost=0.00..1.09 rows=9 widt...
-> Index Only Scan using seats_pkey on seats s
(cost=0.28..10.64 rows=149 width=4)
Index Cond: (aircraft_code = ml.aircraft_code)
(5 rows)
=> EXPLAIN (analyze, costs off, timing off, summary off, buffers off)
SELECT * FROM aircrafts a
WHERE EXISTS (
SELECT * FROM seats s WHERE s.aircraft_code = a.aircraft_code
);
QUERY PLAN
---------------------------------------------------------------
Nested Loop Semi Join (actual rows=9.00 loops=1)
-> Seq Scan on aircrafts_data ml (actual rows=9.00 loops=1)
-> Index Only Scan using seats_pkey on seats s
(actual rows=1.00 loops=9)
Index Cond: (aircraft_code = ml.aircraft_code)
Heap Fetches: 9
Index Searches: 9
(7 rows)
=> EXPLAIN (costs off) SELECT t.passenger_name
FROM tickets t
JOIN ticket_flights tf ON tf.ticket_no = t.ticket_no
JOIN flights f ON f.flight_id = tf.flight_id
WHERE f.flight_id = 12345;
QUERY PLAN
---------------------------------------------------------------------
Gather
Workers Planned: 2
-> Nested Loop
-> Nested Loop
-> Parallel Seq Scan on ticket_flights tf
Filter: (flight_id = 12345)
-> Index Scan using tickets_pkey on tickets t
Index Cond: (ticket_no = tf.ticket_no)
-> Materialize
-> Index Only Scan using flights_flight_id_status_idx ...
Index Cond: (flight_id = 12345)
(11 rows)