j'aurais tendance a te dire de tester
Mais je t'assure que cela marche...
Enfait exists ou not exists verifie par rapport au fait que ta sous requete te ramene qqchose (n'importe quoi) ou rien du tout. C'est soit un ensemble qui veut dire vrai soit rien du tout qui veut dire false.
Sinon dans n'importe quel requete tu peut ramener autre chose que ce qu'il y a dans les colonnes de la table. L'interet est limité en general sauf sur exists ou not exists.
rien ne t'empeche de faire
select 'toto', col1, col2 from table where ...
L'interet majeur de ce system sur les exists ou not exists c'est que ta sous requete ne ramenant pas de colonne de la table tu n'as pas de lecture physique de la dite table, donc gain de perf et pas de prise de place en memoire des dites donnees (=> gain de perf aussi).
Pour la perf entre not in et exists franchement faudrait regarder ce que fait reellement la base, j'ai vu des cas sur Oracle (que je connais bien mieux que MySQL) ou l'un etait meilleur que l'autre et vice-versa. Ca depend pas mal de ta volumetrie dans la table ainsi que de sa structure (donnees et index primaire etc...). Donc faudrait lire les optimisation des requetes que fait MySQL pour savoir. De toutes manieres des que tu as un NOT c'est moins bon que lorsque tu ne l'as pas

Normalement sur la requete avec NOT IN la sous requete doit etre effectuer qu'une seule et unique fois. Et apres les tests se font par rapport au sous ensemble ramene. Par contre on verifiera la totalite des donnees ramenees pour toutes les lignes de la table user.
Avec le not exists la sous requete sera faite autant de fois que le nombre d'user dans la premiere table, mais elle utilise un index.
En l'occurence pour la table groups_users_link elle a quand meme un pb de construction cette table... sa cle primaire ne sert a rien tel quel... il ne devrait y avoir sur cette table qu'une cle primaire comprenant les 2 champs groupid et uid. C'est largement suffisant et ca serait un peu plus performant pour tous les acces fait sur cette table...