El tipo de datos uuid
se adapta perfectamente a la tarea. Solo ocupa 16 bytes en lugar de 37 bytes en RAM para la representación varchar
o text
. (O 33 bytes en el disco, pero el número impar requeriría relleno en muchos casos para que sea de 40 bytes de manera efectiva). Y el uuid
tipo tiene algunas ventajas más.
Ejemplo:
SELECT md5('Store hash for long string, maybe for index?')::uuid AS md5_hash
Detalles y más explicaciones:
Puede considerar otras funciones de hash (más baratas) si no necesita el componente criptográfico de md5, pero usaría md5 para su caso de uso (principalmente de solo lectura).
Una palabra de advertencia : para su caso ( immutable once written
) un PK funcionalmente dependiente (pseudo-natural) está bien. Pero lo mismo sería un dolor donde las actualizaciones text
son posibles. Piense en corregir un error tipográfico: el PK y todos los índices dependientes, las columnas FK dozens of other tables
y otras referencias también tendrían que cambiar. Tabla e índice de hinchazón, problemas de bloqueo, actualizaciones lentas, referencias perdidas, ...
Si text
puede cambiar en la operación normal, un PK sustituto sería una mejor opción. Sugiero una bigserial
columna (rango -9223372036854775808 to +9223372036854775807
- eso es nueve quintillones doscientos veintitres cuatrillones trescientos setenta y dos billones treinta y seis billones ) valores distintos para billions of rows
. En cualquier caso, puede ser una buena idea : ¡ 8 en lugar de 16 bytes para docenas de columnas e índices FK!). O un UUID aleatorio para cardinalidades mucho más grandes o sistemas distribuidos. Siempre puede almacenar dicho md5 (as uuid
) adicionalmente para buscar filas en la tabla principal del texto original rápidamente. Relacionado:
En cuanto a su consulta :
Para abordar el comentario de @ Daniel : Si prefiere una representación sin guiones, elimine los guiones para mostrar:
SELECT replace('90b7525e-84f6-4850-c2ef-b407fae3f271', '-', '')
Pero no me molestaría. La representación predeterminada está bien. Y el problema no es realmente la representación aquí.
Si otras partes deben tener un enfoque diferente y tirar cadenas sin guiones en la mezcla, tampoco es un problema. Postgres acepta varias representaciones de texto razonables como entrada para a uuid
. La documentación :
PostgreSQL también acepta las siguientes formas alternativas de entrada: uso de dígitos en mayúscula, el formato estándar rodeado de llaves, omitiendo algunos o todos los guiones, agregando un guión después de cualquier grupo de cuatro dígitos. Ejemplos son:
A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11
{a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}
a0eebc999c0b4ef8bb6d6bb9bd380a11
a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
{a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}
Además, la md5()
función regresa text
, la usaría decode()
para convertir bytea
y la representación predeterminada de eso es:
SELECT decode(md5('Store hash for long string, maybe for index?'), 'hex')
\220\267R^\204\366HP\302\357\264\007\372\343\362q
Debería encode()
volver a obtener la representación del texto original:
SELECT encode(my_md5_as_bytea, 'hex');
Para colmo, los valores almacenados como bytea
ocuparían 20 bytes en RAM (y 17 bytes en el disco, 24 con relleno ) debido a la sobrecarga internavarlena
, que es particularmente desfavorable para el tamaño y el rendimiento de los índices simples.
Todo funciona a favor de un uuid
aquí.
text
columnas, incluso si no es un "texto" en absoluto.SELECT encode(decode('tZmffOd5Tbh8yXaVlZfRJQ==', 'base64'), 'hex')::uuid;
.uuid
es un tipo de 16 bytes que no puede almacenar los resultados de ningún algoritmo SHA que produzca entre 160 y 512 bits. No hay un tipo similar que se ajuste a la distribución estándar de Postgres. Podría crear uno ... En su defecto, por defectobytea
, como lo hace pg_crypto .Almacenaría el MD5 en una
text
ovarchar
columna. No hay diferencia de rendimiento entre los distintos tipos de datos de caracteres. Es posible que desee restringir la longitud de los valores md5 utilizandovarchar(xxx)
para asegurarse de que el valor md5 nunca exceda una cierta longitud.Las listas IN grandes generalmente no son realmente rápidas, es mejor hacer algo como esto:
Otra opción que a veces se dice que es más rápida es usar una matriz:
Como solo está comparando la igualdad, un índice BTree regular debería estar bien. Ambas consultas deberían poder utilizar dicho índice (especialmente si seleccionan solo una pequeña fracción de las filas).
fuente
bit
tipo, así que no puedo comentar sobre eso. Dado el número esperado de filas, la sugerencia de Erwin parece ser mejor debido al ahorro de espacio que obtienes al almacenar esto como UUIDOtra opción es usar 4 columnas INTEGER o 2 BIGINT.
fuente