kirilisa
04-27-2008, 08:30 PM
Can anyone tell me what is the difference between the two SQL statements? One has an INNER JOIN as opposed to a LEFT JOIN for one of its joins, and they do the self-join in opposite orders, but otherwise they are the same (and return the same stuff, albeit not in the same order). I ran EXPLAIN on them both. is EXPLAIN indicating that the first is more efficient? (b/c in practice it feels like the second is) And if they are so similar why does EXPLAIN show such difference anyway? Why isn't the ContactFK_1 index being used on table c in the second statement?
When doing multiple joins, are the joins done first on the full tables, and then any applicable WHERE criteria is applied? Or is the WHERE criteria applied before/during the join? When is it better to do a join on a subselect (thus applying the WHERE criteria earlier)? Yeek.
mysql> EXPLAIN SELECT
pc.contactId as ci,
c.contactId,
c.firstName, c.lastName,
pc.firstName as fn, pc.lastName as ln,
a.searchAddress,
n.value
FROM (`Contact` pc)
LEFT JOIN `Contact` c ON pc.contactId = c.primaryContactId
LEFT JOIN `Address` a ON a.contactId = pc.contactId
LEFT JOIN `ContactNumber` n ON n.contactId = pc.contactId
WHERE
(a.invalidFlag is null or a.invalidFlag = 0)
AND
c.searchName LIKE '%wilkinso%';
+----+-------------+-------+-------+------------------------+------------------------+---------+--------------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+------------------------+------------------------+---------+--------------------+-------+-------------+
| 1 | SIMPLE | pc | index | PRIMARY | Contact_NameI | 46 | NULL | 61055 | Using index |
| 1 | SIMPLE | a | ref | Address_FKIndex1 | Address_FKIndex1 | 4 | fcprd.pc.contactId | 1 | Using where |
| 1 | SIMPLE | n | ref | ContactNumber_FKIndex1 | ContactNumber_FKIndex1 | 4 | fcprd.pc.contactId | 1 | |
| 1 | SIMPLE | c | ref | Contact_FKIndex1 | Contact_FKIndex1 | 5 | fcprd.pc.contactId | 1 | Using where |
+----+-------------+-------+-------+------------------------+------------------------+---------+--------------------+-------+-------------+
mysql> EXPLAIN SELECT
pc.contactId as ci,
c.contactId,
c.firstName, c.lastName,
pc.firstName as fn, pc.lastName as ln,
a.searchAddress,
n.value
FROM Contact AS c
INNER JOIN Contact AS pc on c.primaryContactId = pc.contactId
LEFT JOIN Address AS a on pc.contactId = a.contactId
LEFT JOIN ContactNumber AS n on pc.contactId = n.contactId
WHERE
(a.invalidFlag is null or a.invalidFlag = 0)
and
(c.searchName LIKE '%wilkinso%')
+----+-------------+-------+--------+------------------------+------------------------+---------+--------------------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+------------------------+------------------------+---------+--------------------------+-------+-------------+
| 1 | SIMPLE | c | ALL | Contact_FKIndex1 | NULL | NULL | NULL | 61055 | Using where |
| 1 | SIMPLE | pc | eq_ref | PRIMARY | PRIMARY | 4 | fcprd.c.primaryContactId | 1 | |
| 1 | SIMPLE | a | ref | Address_FKIndex1 | Address_FKIndex1 | 4 | fcprd.c.primaryContactId | 1 | Using where |
| 1 | SIMPLE | n | ref | ContactNumber_FKIndex1 | ContactNumber_FKIndex1 | 4 | fcprd.c.primaryContactId | 1 | |
+----+-------------+-------+--------+------------------------+------------------------+---------+--------------------------+-------+-------------+
When doing multiple joins, are the joins done first on the full tables, and then any applicable WHERE criteria is applied? Or is the WHERE criteria applied before/during the join? When is it better to do a join on a subselect (thus applying the WHERE criteria earlier)? Yeek.
mysql> EXPLAIN SELECT
pc.contactId as ci,
c.contactId,
c.firstName, c.lastName,
pc.firstName as fn, pc.lastName as ln,
a.searchAddress,
n.value
FROM (`Contact` pc)
LEFT JOIN `Contact` c ON pc.contactId = c.primaryContactId
LEFT JOIN `Address` a ON a.contactId = pc.contactId
LEFT JOIN `ContactNumber` n ON n.contactId = pc.contactId
WHERE
(a.invalidFlag is null or a.invalidFlag = 0)
AND
c.searchName LIKE '%wilkinso%';
+----+-------------+-------+-------+------------------------+------------------------+---------+--------------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+------------------------+------------------------+---------+--------------------+-------+-------------+
| 1 | SIMPLE | pc | index | PRIMARY | Contact_NameI | 46 | NULL | 61055 | Using index |
| 1 | SIMPLE | a | ref | Address_FKIndex1 | Address_FKIndex1 | 4 | fcprd.pc.contactId | 1 | Using where |
| 1 | SIMPLE | n | ref | ContactNumber_FKIndex1 | ContactNumber_FKIndex1 | 4 | fcprd.pc.contactId | 1 | |
| 1 | SIMPLE | c | ref | Contact_FKIndex1 | Contact_FKIndex1 | 5 | fcprd.pc.contactId | 1 | Using where |
+----+-------------+-------+-------+------------------------+------------------------+---------+--------------------+-------+-------------+
mysql> EXPLAIN SELECT
pc.contactId as ci,
c.contactId,
c.firstName, c.lastName,
pc.firstName as fn, pc.lastName as ln,
a.searchAddress,
n.value
FROM Contact AS c
INNER JOIN Contact AS pc on c.primaryContactId = pc.contactId
LEFT JOIN Address AS a on pc.contactId = a.contactId
LEFT JOIN ContactNumber AS n on pc.contactId = n.contactId
WHERE
(a.invalidFlag is null or a.invalidFlag = 0)
and
(c.searchName LIKE '%wilkinso%')
+----+-------------+-------+--------+------------------------+------------------------+---------+--------------------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+------------------------+------------------------+---------+--------------------------+-------+-------------+
| 1 | SIMPLE | c | ALL | Contact_FKIndex1 | NULL | NULL | NULL | 61055 | Using where |
| 1 | SIMPLE | pc | eq_ref | PRIMARY | PRIMARY | 4 | fcprd.c.primaryContactId | 1 | |
| 1 | SIMPLE | a | ref | Address_FKIndex1 | Address_FKIndex1 | 4 | fcprd.c.primaryContactId | 1 | Using where |
| 1 | SIMPLE | n | ref | ContactNumber_FKIndex1 | ContactNumber_FKIndex1 | 4 | fcprd.c.primaryContactId | 1 | |
+----+-------------+-------+--------+------------------------+------------------------+---------+--------------------------+-------+-------------+