Почему использовать UUID вместо int для идентификаторов
Что проверяют
Понимаете ли вы, что выбор типа идентификатора это компромисс, а не мода, и знаете ли, чем именно случайный ключ дорог для базы. Ответ «UUID уникален» засчитывается за половину.
Как отвечать
Начните с задачи, которую решает UUID: идентификатор можно сгенерировать где угодно и заранее, не спрашивая базу. Отсюда независимость сервисов и шардов, отсутствие центрального генератора как узкого места, возможность собрать граф связанных записей в памяти и вставить одной транзакцией, а также идемпотентность: клиент присылает идентификатор сам, и повтор запроса не создаёт вторую запись. Последовательный счётчик, наоборот, выдаёт наружу число созданных объектов и позволяет перебирать чужие записи там, где проверку прав забыли.
Цена тоже конкретная. Шестнадцать байт против восьми у bigint, причём не только в самой колонке, а в каждом вторичном индексе. Хуже другое: случайный ключ вставляется в произвольную страницу дерева, поэтому кэш перестаёт работать, растут расщепления страниц и объём журнала. Лечится версией, упорядоченной по времени: старшие биты там это отметка времени, вставки идут в конец, а генерация без базы сохраняется.
Про Go добавьте, что в стандартной библиотеке типа нет, берут внешний пакет, а случайность тянут из crypto/rand, не из обычного генератора. В PostgreSQL хранить надо в типе uuid.
Где спотыкаются
Хранят UUID строкой в varchar. Это вдвое больше в таблице и в каждом индексе, плюс сравнение строк вместо сравнения шестнадцати байт; типичная находка при разборе медленных запросов.
Второе: считают непредсказуемым любой UUID. Непредсказуема только случайная версия. В упорядоченной по времени угадываются соседи по моменту создания, а ранние версии содержат отметку времени и адрес машины. Идентификатор в любом случае не заменяет проверку прав.
Третье: берут UUID для всего подряд. Для справочника на десяток строк или для таблицы, живущей в одной базе без внешних потребителей, он только добавляет байты и мешает читать логи глазами.