¿Debo invertir el tiempo para cambiar el tipo de columna de CHAR (36) a UUID?


14

Ya tengo algunos millones de filas en mi base de datos. No sabía sobre el tipo de datos UUID de PostgreSQL cuando diseñé mi esquema.

Una de las tablas tiene 16 millones de filas (aproximadamente de 3,5 millones a 4 millones de registros por fragmento), que crece a unos 500 000 registros por día. Todavía tengo el lujo de bajar el sistema de producción durante unas horas si es necesario. No tendré este lujo en una o dos semanas.

Mi pregunta es, ¿valdrá la pena hacerlo? Me pregunto sobre el rendimiento de JOIN, el uso del espacio en disco (el volcado gzip'd completo es 1.25 GiB), cosas de esa naturaleza.

El esquema de la tabla es:

# \d twitter_interactions
                Table "public.twitter_interactions"
         Column          |            Type             | Modifiers 
-------------------------+-----------------------------+-----------
 interaction_id          | character(36)               | not null
 status_text             | character varying(1024)     | not null
 screen_name             | character varying(40)       | not null
 twitter_user_id         | bigint                      | 
 replying_to_screen_name | character varying(40)       | 
 source                  | character varying(240)      | not null
 tweet_id                | bigint                      | not null
 created_at              | timestamp without time zone | not null
Indexes:
    "twitter_interactions_pkey" PRIMARY KEY, btree (interaction_id)
    "twitter_interactions_tweet_id_key" UNIQUE, btree (tweet_id)
    "index_twitter_interactions_on_created_at" btree (created_at)
    "index_twitter_interactions_on_screen_name" btree (screen_name)
Triggers:
    insert_twitter_interactions_trigger BEFORE INSERT ON twitter_interactions FOR EACH ROW EXECUTE PROCEDURE twitter_interactions_insert_trigger()
Number of child tables: 9 (Use \d+ to list them.)

Respuestas:


13

Consideraría cambiar al tipo de UUID. char(36)toma 40 bytes, uuidtoma 16, por lo que ahorrará 24 bytes por fila, lo que para usted equivaldrá a 12 MB por día, 4 GB después de un año. Índices más. Dependiendo del hardware que tenga, eso no es mucho, pero podría ser. Y se suma si tiene más oportunidades de mejora como esta.

Además, no veo ninguna restricción en su esquema que garantice que interaction_idesté realmente en el formato correcto. Usar el tipo correcto también te dará eso.

Sin embargo, si le gusta esto, usarlo bigintle ahorraría aún más y tendría un rendimiento aún mejor. Es muy poco probable que su aplicación sea tan grande que una bigintcolumna de ID no funcione.


Tengo un sistema distribuido: múltiples fuentes de datos generan ID para las interacciones, por lo tanto, no puedo usar un BIGINT simple a menos que haya reservado N bits para la ID del nodo.
François Beausoleil

3
@ FrançoisBeausoleil, reservar N bits para la ID del nodo es igual a usar cada enésimo número en una secuencia (y, por lo tanto, fácil de implementar). Además, puede considerar usar claves compuestas.
motivo

1
La coordinación de secuencias múltiples (con ID de nodo) es una molestia administrativa en la práctica y propensa a errores humanos. No veo ninguna razón para no usar UUID en este escenario, especialmente porque los bits son baratos hoy en día (tanto memoria como almacenamiento). De hecho, este escenario es la razón por la cual los UUID se inventaron hace décadas: para compartir datos entre sistemas distribuidos sin coordinación centralizada .
Basil Bourque

6

No soy una persona de postgres en ningún sentido de la imaginación, pero según lo que sé de SQL Server, cuantas más filas quepa en una página de datos, mejor rendimiento tendrá (la lectura de datos del disco suele ser operación más cara). Por lo tanto, pasar de un campo ancho de 36 ish 1 byte a 16 byte GUID parece un ahorro de costos directo. Cuantas menos lecturas pueda incurrir, más rápido podrá devolver resultados. Todo esto, por supuesto, supone que un GUID / UUID satisface las necesidades comerciales de la tabla. Si un UUID lo satisface, ¿sería un bigint ? Eso afeitaría aún más su almacenamiento cuesta otros 8 bytes por fila.

Editar 1

Para los datos de personajes en Postgres, hay un costo de almacenamiento adicional para ellos. Las cadenas cortas, de menos de 127 bytes tienen una sobrecarga de 1 byte, mientras que cualquier cosa más larga tiene 4 bytes, que es cómo el segundo encuestado obtuvo un costo de 40 bytes para un campo de 36 bytes. Pero también hay una opción para la compresión de cadenas, por lo que tal vez no cueste los 40 totales. No puedo decir cuál sería el costo final, pero los fundamentos permanecen: cualquier cosa de más de 16 bytes aumentará el costo de almacenamiento, tomará más tiempo leer de y consumir más memoria.

El requisito de almacenamiento para una cadena corta (hasta 126 bytes) es de 1 byte más la cadena real, que incluye el relleno de espacio en el caso de caracteres. Las cadenas más largas tienen 4 bytes de sobrecarga en lugar de 1. Las cadenas largas son comprimidas por el sistema automáticamente, por lo que el requerimiento físico en el disco podría ser menor.


3

Además del problema del espacio, tenga en cuenta que tendrá que cambiar cada tabla para usar el tipo de datos correcto o su rendimiento de unión se verá afectado.


Eso fue un hecho, pero gracias por recordármelo.
François Beausoleil

3
Al hacer cambios importantes como este, encuentro que escribir todo (no importa cuán simple sea recordarlo) generalmente vale la pena.
mrdenny

3

Además del ahorro en tamaño de datos e índices (como lo han dicho otros), que se traduce en ahorros de E / S, lo que debe considerar es cómo generará nuevos valores interaction_idy cuál será el impacto en el índices y condiciones de consulta (uniones).

Para el índice, será más pequeño, sin embargo, si muchas de sus consultas usan escaneos de índice, cambiar a UUID podría hacer que los escaneos de índice sean imposibles (dependiendo de cómo generará UUID) y bigintpodría ser una opción mucho mejor.

Finalmente, como el impacto real en el rendimiento depende también de sus patrones de uso y distribución de datos, debe ejecutar pruebas y tener un entorno de desarrollo y prueba en el que pueda probar sus cambios.

Esto le dará una respuesta mucho más exacta sobre el impacto en el rendimiento.


Gracias por la útil contribución y bienvenidos al sitio :)
Jack dice que intente topanswers.xyz

Mis patrones de acceso son a través de rangos de fechas, uniéndome usando screen_name o por UUID. No se anticipan escaneos de rango en la ID única. Gracias por su respuesta, muy informativo.
François Beausoleil
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.