DISTINCT прибирає однакові рядки результату. GROUP BY збирає рядки в групи, щоб порахувати для кожної агрегати.
Без агрегатів вони дають однаковий результат, і MySQL часто виконує їх однаково:
SELECT DISTINCT city FROM customers;
SELECT city FROM customers GROUP BY city;
Різниця з'являється, коли потрібні агрегати:
SELECT city, COUNT(*) AS customers, MAX(created_at) AS last_signup
FROM customers
GROUP BY city;
DISTINCT порахувати нічого не вміє - лише прибрати повтори.
DISTINCT діє на весь рядок, а не на першу колонку:
SELECT DISTINCT city, name FROM customers; -- унікальні пари (місто, ім'я)
Поширена помилка - очікувати «унікальні міста з будь-яким ім'ям».
COUNT(DISTINCT ...) - кількість унікальних значень:
SELECT COUNT(DISTINCT user_id) AS buyers FROM orders WHERE created_at >= '2026-10-01';
Запах у запитах - DISTINCT для «лікування» дублікатів після JOIN:
SELECT DISTINCT u.* FROM users u JOIN orders o ON o.user_id = u.id;
JOIN з таблицею «багато» розмножує рядки, а DISTINCT їх потім прибирає - база спершу робить зайву роботу, а потім ще й сортує результат. Правильно сформулювати, що потрібно: «користувачі, у яких є замовлення»:
SELECT u.* FROM users u WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);
Швидкодія: обидва можуть використати індекс за колонками групування; без нього - тимчасова таблиця. У EXPLAIN це видно як Using temporary.