UUID. Текстове подання - 36 символів (CHAR(36)), тобто 36 байтів на значення, а в utf8mb4-колонці ще й з накладними витратами порівняння за collation. Бінарне - 16 байтів:
CREATE TABLE documents (
id BINARY(16) PRIMARY KEY,
title VARCHAR(255) NOT NULL
);
INSERT INTO documents (id, title) VALUES (UUID_TO_BIN(UUID(), 1), 'Договір');
SELECT BIN_TO_UUID(id, 1) AS id, title FROM documents;
Чому розмір первинного ключа в InnoDB важливий подвійно: кожен вторинний індекс містить копію первинного ключа. 36 байтів замість 16 (чи 8 для BIGINT) множаться на всі індекси таблиці.
Прапорець 1 (swap) у UUID_TO_BIN. MySQL-функція UUID() генерує UUID версії 1, де мітка часу розкидана по рядку так, що значення не зростають. Перестановка частин робить їх впорядкованими за часом - нові рядки дописуються в кінець кластерного індексу, а не в випадкові місця. Для UUIDv4 (повністю випадкових) прапорець не допомагає - для них краще генерувати впорядковані UUIDv7 у застосунку.
Незручність бінарних UUID: у консолі вони нечитабельні, і в кожному запиті потрібні перетворення. Laravel з HasUuids за замовчуванням використовує CHAR(36); бінарне зберігання потребує власного касту.
IP-адреси:
CREATE TABLE logins (
ip VARBINARY(16) NOT NULL, -- IPv4 (4 байти) і IPv6 (16 байтів)
created_at DATETIME NOT NULL
);
INSERT INTO logins (ip, created_at) VALUES (INET6_ATON('2001:db8::1'), NOW());
SELECT INET6_NTOA(ip) FROM logins;
-- пошук у підмережі - діапазоном по бінарному значенню
SELECT * FROM logins
WHERE ip BETWEEN INET6_ATON('192.168.1.0') AND INET6_ATON('192.168.1.255');
INET6_ATON працює і з IPv4, і з IPv6. Старі INET_ATON / UNSIGNED INT - лише для IPv4.
PostgreSQL має для цього рідні типи: uuid (16 байтів, з UUIDv7 у PG18) і inet/cidr з операторами підмереж - перетворення там не потрібні.
Докладніше в документації: Інші функції: UUID_TO_BIN, INET6_ATON