Niby dlaczego, najpierw masz unikalną listę krajów w CTE, a potem dla każdego sprawdzasz, czy nie istnieje wpis powiązany z WHO. Jak chcesz to zrobić optymalniej - przez JOINy? To dopiero jest nieoptymalne bo dla każdego wiersza musisz robić JOIN zamiast robić sprawdzenie przez negację tylko raz dla danego kraju.
@TomRZ: w komentarzu sie nie zmieszczę...
Fajnie, że opisałeś jak Ci się wydaje że jest robione, jednak my rozmawiamy o SQL, a w nim mamy marny wpływ na to jak silnik te dane pobierze i optymalizator zoptymalizuje. Jedno jest pewne, należy starać się unikać przeczeń, bo to o ile optymalizowane, to jednak jest to trudne do osiągnięcia. Analizując przykład na testowych danych:
CREATE TABLE `ismember` (
`kraj` varchar(1) NOT NULL,
`organizacja` int(2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin2;
INSERT INTO `ismember` (`kraj`, `organizacja`) VALUES
('A', 1),('B', 1),('C', 1),('D', 1),('E', 1),('F', 1),('G', 1),('H', 1),('I', 1),('J', 1)
,('A', 2),('B', 2),('C', 2),('D', 2),('E', 2),('F', 2),('G', 2),('H', 2),('I', 2),('J', 2),
('A', 3),('B', 3);
Zróbmy te zapytania:
-- bez join
WITH dctr AS (
SELECT DISTINCT(`Country`) FROM ismember
)
SELECT dctr.`Country` FROM dctr WHERE NOT EXISTS (SELECT * FROM ismember WHERE `Country` = dctr.`Country`
AND `Organisation` = 3);
--z join
WITH dctr AS (
SELECT DISTINCT(`Country`) FROM ismember
)
SELECT dctr.`Country` FROM dctr
left join (select country from ismember where organisation=3) who on who.country = dctr.country
where who.country is null;
Statystyki:
Bez join
z join
|
not exists |
left join |
Rows sent to client |
8 |
8 |
Rows examined |
34 |
32 |
Temporary tables created |
3 |
2 |
Full table scans |
2 |
2 |
Joins using table scans scans |
1 |
1 |
Więc jak widzisz, join nie odstaje tutaj, a nawet tworzy jedną tabelę tymczasową mniej.
I to miałem na myśli psząc że przeczenie + optymalizacja to nie bardzo. Warto to zapamiętać, a przede wszystkim sprawdzać co robi silnik, a nie co się nam wydaje że robi.