INNER JOIN vs LEFT JOIN, plus a peek under the hood at the join algorithms.
An INNER JOIN returns only rows that have a matching value in both tables. If no match is found, the row is excluded.
-- Modern explicit inner join
SELECT p.name AS pet_name, o.full_name AS owner_name
FROM pets AS p
JOIN owners AS o
ON p.owner_id = o.owner_id;
Old style that is functionally the same as INNER JOIN:
SELECT p.name, o.full_name
FROM pets AS p, owners AS o
WHERE p.owner_id = o.owner_id;
A LEFT JOIN keeps all rows from the left table and matches from the right table. If no
match is found on the right side, the right table columns are returned as NULL.
SELECT o.full_name, p.name AS pet_name
FROM owners AS o
LEFT JOIN pets AS p
ON o.owner_id = p.owner_id;
Read it left to right - keep every owner, and if they have pets show them, otherwise pet columns are NULL.
The optimizer chooses a join algorithm based on table sizes, indexes, and statistics. The three common strategies are below.
for each row a in A
probe B using a.join_key -- ideally via index
output matches
build hash from B on join_key
for each row a in A
lookup a.join_key in hash
output matches
while i < A and j < B
if A[i].key == B[j].key -> output and advance
else if A[i].key < B[j].key -> i++
else j++
You can see what your engine chose using EXPLAIN:
EXPLAIN
SELECT p.name, o.full_name
FROM pets AS p
JOIN owners AS o
ON p.owner_id = o.owner_id;
| pets | owners |
|---|---|
pet_id | name | owner_id1 | Luna | 1 2 | Rex | 2 3 | StrayCat | NULL |
owner_id | full_name1 | Kara 2 | James |
SELECT p.name, o.full_name
FROM pets p
JOIN owners o ON p.owner_id = o.owner_id;
Result - only matches:
Luna | Kara Rex | James
SELECT o.full_name, p.name
FROM owners o
LEFT JOIN pets p ON o.owner_id = p.owner_id;
Result - all owners, pets may be NULL:
Kara | Luna James | Rex
If there was an owner with no pets, they would still appear with NULL
for the pet name.
EXPLAIN.