2009-06-29 8 views
9

Estoy planificando una base de datos para almacenar gran cantidad de texto. (entradas de blog, artículos de noticias, etc.) La base de datos debe tener el título, el contenido (máximo de 50k caracteres), fecha, enlace y campos de idioma. El mismo contenido no puede ocurrir en un enlace. El contenido antiguo (anterior a 30 días, por ejemplo) se eliminará.PostgreSQL: Definición de una clave principal en una base de datos grande

Ahora, el problema es la clave principal. Podría simplemente establecer un campo de incremento automático (tipo SERIAL) y usarlo como clave principal. Pero parece estúpido y un desperdicio de espacio en disco, porque el campo no serviría para nada más que ser una clave principal. (y el campo podría eventualmente agotarse, o no?) Y siempre existe el otro problema de rendimiento: el contenido de cada nueva fila insertada debe verificarse para ver si hay duplicados. Así que la otra solución para la clave principal que se me ocurrió sería calcular un hash sha256 de contenido + valor de enlace y luego poner eso en una nueva columna 'hash' y usar eso como clave principal. Dos pájaros con una piedra. Por supuesto, el problema con eso son colisiones hash. ¿Es una gran amenaza?

No tengo ninguna experiencia con PostgreSQL, y muy poca experiencia con DBMS en general, por lo que agradecería una segunda opinión antes de crear una base de datos con las características de rendimiento de un caracol en la carretera (comparación horrible).

Por favor, ayúdenme si tiene alguna experiencia con grandes bases de datos. ¿Es una buena idea establecer una cadena de 64 caracteres como clave principal en mi situación? (Porque estoy bajo la impresión de que por lo general esto se evita)

Respuesta

9

acabo de hacer esta prueba exacta de una base de datos en lugar medio-grande (200 GB +), BIGSERIAL ganado por un margen bastante grande. Fue más rápido de generar, más rápido de unirse, menos código, menor huella. Debido a la forma en que Postgres lo almacena, un bigint es insignificante en comparación con un int normal. Se le agotará el espacio de almacenamiento de su contenido mucho antes de que tenga que preocuparse por desbordar el bigint. Habiendo realizado el hash calculado vs bigint - bigint sustituto todo el camino.

+0

¿Incluyeron sus pruebas "el otro problema de rendimiento: el contenido de cada nueva fila insertada necesita [sic] verificar duplicados"? – onedaywhen

2

Algunas sugerencias:

  • El almacenamiento en disco de un número entero clave principal de 64 bits es insignificante, no importa la cantidad de contenido que tiene.
  • Nunca colisionará SHA256, y usarlo como una identificación única no es una mala idea.

Una cosa buena del método hash es que no tiene una fuente de secuencia única para generar claves primarias nuevas. Esto puede ser útil si su base de datos necesita ser segmentada de alguna manera (por ejemplo, distribución geográfica) para futuras escalas, ya que no tiene que preocuparse por las colisiones, o un punto único de falla que genera secuencias.

Desde una perspectiva de codificación, tener una sola clave principal puede ser vital para unir las tablas adicionales de datos que puede agregar en el futuro. Te recomiendo que uses uno. Hay beneficios para cualquiera de los enfoques propuestos, pero el método hash podría ser el preferido, solo porque los valores autoincrement/sequence pueden ocasionar problemas de escalabilidad a veces.

+1

Si usa SHA256 como clave principal, ¿no tiene que ser inmutable? ¿Qué sucede si el contenido + el valor del enlace cambia? –

+0

Harvey, buen punto, pero si quisiera cambiar el valor del contenido de una fila, entonces verificaría si todavía existe un hash del nuevo contenido + enlace. Si es así, no ocurriría ningún cambio. – KRTac

+0

Entonces, si el contenido cambia, ¿crea un nuevo registro? –

1

Los valores hash son malas ideas para las claves principales. Hacen que los insertos terminen en orden aleatorio en la tabla, y eso se vuelve muy costoso ya que las cosas tienen que ser reasignadas (aunque Postgres en realidad no se aplica de la misma manera que otros). Sugiero una clave primaria secuencial que puede ser una marca de tiempo/indicación de fecha y hora precisa con un número secuencial siguiente, que te permite matar dos pájaros con una piedra, y un segundo índice único que contiene tus códigos hash. Tenga en cuenta que desea mantener su clave principal como una columna más pequeña (64 bits o menos).

Consulte la tabla en http://en.wikipedia.org/wiki/Birthday_attack#The_mathematics para que pueda estar seguro de que no tendrá una colisión.

No olvide aspirar.

3

Tendría que tener una gran cantidad de registros antes de que se agotara su número de clave principal.

El número entero será más rápido para las uniones que una clave primaria de cadena de 64 caracteres.También es mucho más fácil para las personas que escriben consultas.

Si alguna vez es posible una colisión, no puede usar el hash como clave principal. Las claves primarias deben estar protegidas para ser únicas por definición.

He visto cientos de bases de datos de producción para diferentes corporaciones y entidades gubernamentales y ninguna ha utilizado una clave principal hash. ¿Crees que podría haber una razón?

embargo, parece estúpida y una pérdida de espacio en el disco, porque el campo no se sirve a ningún propósito que sea una clave principal.

Dado que una clave primaria sustituta siempre debe tener sentido, excepto como clave principal, no estoy seguro de cuál será su objeción.

+0

Estoy planeando tener MUCHAS filas en la mesa. La fila anterior se eliminará, pero el campo continuará incrementando automáticamente el recuento de filas, de modo que cuando el campo en serie llegue al 2147483647 no puedo obtener más filas en la tabla, aunque la tabla esté medio vacía. – KRTac

+1

Se refiere a un entero de 32 bits con signo. Para un entero con signo de 64 bits, el valor máximo es 9,223,372,036,854,775,807. Dudo que alguna vez agotaras eso. –

+1

¿Sería más rápido que un hash, evan aunque es de 64 bits int? – KRTac

3

Yo elegiría utilizar una clave sustituta, es decir. una clave que no forma parte de los datos comerciales de su aplicación. Los requisitos de espacio adicional de un entero adicional de 64 bits cuando se trata de hasta 50 kilobytes de texto por registro son insignificantes. De hecho, estará utilizando menos espacio tan pronto como empiece a utilizar esta clave como una clave foránea en otras tablas.

El uso de un hash de los datos almacenados en un registro es un candidato muy malo para una clave principal, en caso de que los datos en los que se basa el hash cambien alguna vez. También habrá cambiado la clave principal, lo que generará actualizaciones en todo el lugar si tiene relaciones de otras tablas con esta.

PS. Se ha realizado y respondido una pregunta similar aquí before.

Aquí hay otro buen reportaje sobre el tema: http://www.agiledata.org/essays/keys.html

+0

Un gran consejo, y estoy de acuerdo con la mayor parte. Pero, como mencioné anteriormente, ¿qué pasa cuando la clave Surganat alcanza el 2147483647? Podría usar bigserial, pero ¿cuál es el rendimiento alcanzado en eso? – KRTac

+0

En este contexto (almacenamiento de entradas de blog y artículos de noticias) dudo que llegar a 2^31 artículos sería muy probable. Aun así, si desea planificar con anticipación, ir a lo seguro y usar bigserial, diría que el rendimiento será mínimo, especialmente si se compara con el uso de un CHAR (32) como PK. –

1

Utilizaría un entero ordinario de 32 bits como clave principal. No creo que vayas a superar ese número muy pronto :-) Toda la Wikipedia tiene alrededor de 3,5 millones de artículos ... Si escribes 1000 artículos por día, llevaría casi 6000 años alcanzar el máximo del tipo entero.

Cuestiones relacionadas