Hash Join vs Hash Semi Join

8

PostgreSQL 9.2

Próbuję zrozumieć różnicę między Hash Semi Joini sprawiedliwy Hash Join.

Oto dwa zapytania:

ja

EXPLAIN ANALYZE SELECT * FROM orders WHERE customerid IN (SELECT
customerid FROM customers WHERE state='MD');

Hash Semi Join  (cost=740.34..994.61 rows=249 width=30) (actual time=2.684..4.520 rows=120 loops=1)
  Hash Cond: (orders.customerid = customers.customerid)
  ->  Seq Scan on orders  (cost=0.00..220.00 rows=12000 width=30) (actual time=0.004..0.743 rows=12000 loops=1)
  ->  Hash  (cost=738.00..738.00 rows=187 width=4) (actual time=2.664..2.664 rows=187 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 7kB
        ->  Seq Scan on customers  (cost=0.00..738.00 rows=187 width=4) (actual time=0.018..2.638 rows=187 loops=1)
              Filter: ((state)::text = 'MD'::text)
              Rows Removed by Filter: 19813

II

EXPLAIN ANALYZE SELECT * FROM orders o JOIN customers c ON o.customerid = c.customerid WHERE c.state = 'MD'

Hash Join  (cost=740.34..1006.46 rows=112 width=298) (actual time=2.831..4.762 rows=120 loops=1)
  Hash Cond: (o.customerid = c.customerid)
  ->  Seq Scan on orders o  (cost=0.00..220.00 rows=12000 width=30) (actual time=0.004..0.768 rows=12000 loops=1)
  ->  Hash  (cost=738.00..738.00 rows=187 width=268) (actual time=2.807..2.807 rows=187 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 37kB
        ->  Seq Scan on customers c  (cost=0.00..738.00 rows=187 width=268) (actual time=0.018..2.777 rows=187 loops=1)
              Filter: ((state)::text = 'MD'::text)
              Rows Removed by Filter: 19813

Jak widać, jedyną różnicą w planach jest to, że w pierwszym przypadku hastable zużywa 7kB, ale w drugim przypadku 37kBi że węzeł jest Hash Semi Join.

Ale nie rozumiem różnicy w rozmiarze tablicy mieszającej. HashWęzeł wykorzystuje doskonale ten sam Seq Scanwęzeł mający takie same Filter. Dlaczego jest różnica?

St.Antario
źródło
Czy spojrzałeś na rzeczywistą wydajność zapytań? Lub użyj explain (analyze, verbose).
jjanes,

Odpowiedzi:

5

W pierwszym zapytaniu tylko identyfikator_użytkownika musi zostać zapisany customersw tabeli mieszającej, ponieważ są to jedyne dane potrzebne do wdrożenia połączenia częściowego.

W drugim zapytaniu wszystkie kolumny muszą być przechowywane w tabeli mieszającej, ponieważ wybierasz wszystkie kolumny z tabeli (używając *), a nie tylko testujesz na istnienie ID_użytkownika.

jjanes
źródło