SET est la norme ANSI pour l’affectation des variables.
SET ne peut affecter qu’une variable à la fois alors que SELECT peut en effectuer plusieurs.
Pour une requête qui renvoie plusieurs valeurs / lignes, SET génère une erreur.
DECLARE @TAB TABLE(libe VARCHAR(100));
INSERT INTO @tab(libe) VALUES('Test'), ('TOTO'), ('Titi'), ('tutu');
DECLARE @SET VARCHAR(100)
SET @SET = ( SELECT LIBE FROM @TAB )

SELECT affectera l’une des valeurs à la variable et masquera le fait que plusieurs valeurs ont été renvoyées.
DECLARE @TAB TABLE(libe VARCHAR(100));
INSERT INTO @tab(libe) VALUES('Test'), ('TOTO'), ('Titi'), ('tutu');
DECLARE @SELECT VARCHAR(100)
SELECT @SELECT= LIBE FROM @TAB
SELECT @SELECT

Lors de l’affectation à partir d’une requête s’il n’y a pas de valeur renvoyée, SET affectera NULL, alors que SELECT ne fera pas du tout l’affectation (donc la variable ne sera pas modifiée par rapport à sa valeur précédente)
DECLARE @SELECT VARCHAR(100) = 'SELECT'
DECLARE @SET VARCHAR(100) = 'SET'
SELECT @SELECT= 'NEW' WHERE 1=2
SET @SET = (SELECT 'NEW' WHERE 1=2 )
SELECT @SELECT AS [SELECT] , @SET AS [SET]

Il n’y a pas de différences de performance entre SET et SELECT.