Ето и конкретният пример.
В MySQL 5.0.54a-enterprise имаме следните три таблици (опростени), които съхраняват различна информация за различни устройства (работни станции, сървъри, инфраструктурни устройства, и т.н.)
entities
+------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+-------+
| eId | int(11) | NO | PRI | NULL | |
| eName | varchar(255) | NO | MUL | NULL | |
| eType | int(11) | NO | MUL | NULL | |
+------------------+--------------+------+-----+---------+-------+
endpoints
+--------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+-------+
| eId | int(11) | NO | PRI | NULL | |
| address | varchar(39) | NO | MUL | NULL | |
+--------------+---------------------+------+-----+---------+-------+
units
+-------------------------+-------------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+-------------------------------------+------+-----+---------+-------+
| eId | int(11) | NO | PRI | NULL | |
| unitName | varchar(255) | YES | MUL | NULL | |
| unitAddress | varchar(39) | YES | | NULL | |
| unitLocation | varchar(255) | YES | | NULL | |
+-------------------------+-------------------------------------+------+-----+---------+-------+
Искам по подаден LIKE pattern за IP адрес, примерно '110.120.1%' да получа информацията от entities и endPoints таблиците за всички entity-та, които са също налични в endPoints таблицата, но НЕ присъстват в units таблицата.
Вариантите ми са три, според трите подхода за търсене на елемент от таблица, които не са в друга таблица:
LEFT JOIN + IS NULL:
select i.eId, e.eName, e.eType, i.address from endpoints i inner join entities e on e.eId=i.eId left join units u on u.unitAddress=i.address where i.address like '110.120.1%' and u.unitAddress is null;
SELECT + NOT IN:
select i.eId, e.eName, e.eType, i.address from endpoints i inner join entities e on e.eId=i.eId where i.address like '110.120.1%' not in (select unitAddress from units);
SELECT + NOT EXISTS:
select i.eId, e.eName, e.eType, i.address from endpoints i inner join entities e on e.eId=i.eId where i.address like '110.120.1%' and not exists (select unitAddress from units u where u.unitAddress=i.address);
Кой от тези би трябвало да е по-ефективен по принцип (И защо)?
Малко информация за таблиците:
В units имаме приблизително 6000 записа, в entities - прибл. 400000, a в endPoints - прибл. 300000.
В entities имаме абстрактна информация за устройствата и техните компоненти, в endpoints имаме информация за техните IP адреси, а в units имаме само данни за основните компоненти на устройствата - шаситата, т.е. един единствен адрес.
- във всички таблици полето eId е primary key;
- всички eId стойности от endpoints се съдържат в entities;
- всички eId стойности от units се съдържат в entities;
- НЯМА стойности от units, за които units.еId=endPoints.eId;
- но има стойности от units, за които units.unitAddress=endPoint.address,
т.е.: шасито на един сървър с 5 IPta примерно, ще има запис в units с основния си адрес, и с eId, което е налично и в entities; За всеки IP адрес на сървъра, вкл. основния му адрес, има отделни записи в endPoints, с eId ключове, които са налични в entities, но не са налични в units. Иде реч, че entities и endpoints могат да се джойннат на primary key полето еId, но endpoints и units не могат да се джойннат по primary key поле, а само по адрес, което не е primary key и е индекс само в endPoints.