Тип данных uuid
будет отлично подходят для выполнения этой задачи. Он занимает всего 16 байтов, а не 37 байтов в оперативной памяти для представления varchar
или text
. (Или 33 байта на диске, но нечетное число потребует заполнения во многих случаях, чтобы эффективно сделать его 40 байтов.) И у uuid
типа есть еще некоторые преимущества.
Пример:
SELECT md5('Store hash for long string, maybe for index?')::uuid AS md5_hash
Подробности и подробное объяснение:
Вы можете рассмотреть другие (более дешевые) хеш-функции, если вам не нужен криптографический компонент md5, но я бы остановился на md5 для вашего случая использования (в основном только для чтения).
Слово предупреждения : В вашем случае ( immutable once written
) а функционально зависит (псевдо-натуральный) PK прекрасно. Но то же самое было бы болью, где возможны обновления text
. Подумайте об исправлении опечатки: PK и все зависимые от него индексы, столбцы FK dozens of other tables
и другие ссылки также должны быть изменены. Разворот таблиц и индексов, проблемы с блокировками, медленные обновления, потерянные ссылки, ...
Если text
может измениться в нормальной работе, суррогатное ПК будет лучшим выбором. Я предлагаю bigserial
столбец (диапазон -9223372036854775808 to +9223372036854775807
- это девять квинтиллионов двести двадцать три квадриллиона триста семьдесят два триллиона тридцать шесть с лишним миллиардов ) различных значений billions of rows
. В любом случае это может быть хорошей идеей : 8 вместо 16 байтов для десятков столбцов и индексов FK!). Или случайный UUID для гораздо больших мощностей или распределенных систем. Вы всегда можете сохранить указанный md5 (as uuid
) дополнительно, чтобы быстро найти строки в главной таблице из исходного текста. Связанный:
Что касается вашего запроса :
Чтобы ответить на комментарий @ Daniel : Если вы предпочитаете представление без дефисов, удалите дефисы для отображения:
SELECT replace('90b7525e-84f6-4850-c2ef-b407fae3f271', '-', '')
Но я бы не стал беспокоиться. Представление по умолчанию просто отлично. И проблема действительно не в представлении здесь.
Если другие партии должны использовать другой подход и добавлять строки без дефисов, это тоже не проблема. Postgres принимает несколько разумных текстовых представлений в качестве входных данных для a uuid
. Документация :
PostgreSQL также принимает следующие альтернативные формы для ввода: использование цифр в верхнем регистре, стандартный формат, заключенный в фигурные скобки, пропуск некоторых или всех дефисов, добавление дефиса после любой группы из четырех цифр. Примеры:
A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11
{a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}
a0eebc999c0b4ef8bb6d6bb9bd380a11
a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
{a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}
Более того, эти md5()
функции возвращаются text
, вы будете использовать , decode()
чтобы преобразовать в bytea
и представление по умолчанию , что это:
SELECT decode(md5('Store hash for long string, maybe for index?'), 'hex')
\220\267R^\204\366HP\302\357\264\007\372\343\362q
Вы должны были бы encode()
снова получить исходное текстовое представление:
SELECT encode(my_md5_as_bytea, 'hex');
В довершение всего, значения, хранящиеся как bytea
, занимают 20 байт в ОЗУ (и 17 байт на диске, 24 с заполнением ) из-за внутренних varlena
издержек , что особенно неблагоприятно для размера и производительности простых индексов.
Все работает в пользу uuid
здесь.
text
столбцах - даже если они вообще не являются «текстовыми».SELECT encode(decode('tZmffOd5Tbh8yXaVlZfRJQ==', 'base64'), 'hex')::uuid;
.uuid
это 16-байтовый тип, который не может хранить результаты любого алгоритма SHA, генерирующего от 160 до 512 бит. Нет аналогичного типа, который бы подходил для стандартного дистрибутива Postgres. Вы можете создать его ... Если это не так, по умолчаниюbytea
- как и в pg_crypto .Я бы сохранил MD5 в столбце
text
илиvarchar
. Нет различий в производительности между различными типами символьных данных. Вы можете захотеть ограничить длину значений md5, используя,varchar(xxx)
чтобы убедиться, что значение md5 никогда не превышает определенную длину.Большие IN-списки обычно не очень быстрые, лучше сделать что-то вроде этого:
Другой вариант, который иногда называют более быстрым, - это использование массива:
Поскольку вы просто сравниваете равенство, обычный индекс BTree должен быть в порядке. Оба запроса должны иметь возможность использовать такой индекс (особенно если они выбирают только небольшую часть строк).
источник
bit
тип, поэтому я не могу комментировать это. Учитывая ожидаемое количество строк, предложение Эрвина кажется лучше из-за экономии места, которую вы получаете, сохраняя это как UUIDДругой вариант - использовать 4 столбца INTEGER или 2 BIGINT.
источник