Algo assim:
SELECT first_user.id_user, second_user.id_user, COUNT(first_user.id_user) AS total_matches
FROM likes AS first_user
JOIN likes AS second_user
ON second_user.id_artist = first_user.id_artist
AND second_user.id_user != first_user.id_user
GROUP BY first_user.id_user, second_user.id_user
ORDER BY total_matches DESC
LIMIT 1
Observe que isso não é muito eficiente. Uma maneira de contornar isso é fazer uma 'tabela de cache' contendo a saída desta consulta com o
LIMIT 1
parte removida. Adicione alguns índices relevantes e consulte esta tabela de cache. Você pode definir um cron job para atualizar esta tabela periodicamente. Exemplo:
CREATE TABLE IF NOT EXISTS `likes` (
`id_user` varchar(50) DEFAULT NULL,
`id_artist` varchar(50) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `likes` (`id_user`, `id_artist`) VALUES ('8', '39'), ('8', '37'), ('4', '37'), ('8', '24'), ('8', '7'), ('4', '28'), ('8', '28'), ('4', '27'), ('4', '11'), ('8', '49'), ('4', '7'), ('4', '40'), ('4', '29'), ('8', '22'), ('4', '29'), ('8', '11'), ('8', '28'), ('4', '7'), ('4', '31'), ('8', '42'), ('8', '25'), ('4', '25'), ('4', '17'), ('4', '32'), ('4', '46'), ('4', '19'), ('8', '34'), ('3', '32'), ('4', '21')
+---------+---------+---------------+
| id_user | id_user | total_matches |
+---------+---------+---------------+
| 8 | 4 | 7 |
+---------+---------+---------------+