Crear una clave primaria secundaria en una base de datos para algunas tablas

22

A algunas de mis tablas quiero agregar "second_primary_key", que será uuid o alguna clave larga aleatoria. Lo necesito porque para algunas tablas no quiero exponer enteros a mi aplicación web. Es decir, en una página "/ facturas" tengo una lista de facturas y un enlace a "/ facturas /: id" donde: id es un número entero. No quiero que un usuario sepa cuántas facturas hay en mi sistema, por lo tanto, en lugar de "/ invoices / 123", quiero usar su "segunda_primera_clave" para que la URL sea "/ invoices / N_8Zk241vNa"

Lo mismo ocurre con otras tablas donde quiero ocultar la identificación real.

Me pregunto, ¿es esta una práctica común? ¿Cuál es la mejor manera de implementar esto?

¿Y cómo se llama esta técnica después de todo, para que pueda buscarla?

Dari
fuente
20
¿Por qué no deshacerse del entero por completo?
larsbe
44
Puede definir tantas claves / índices únicos como desee en una tabla.
abuzittin gillifirca
2
Quizás debería llamarlo una clave candidata secundaria. "Primario" sugiere solo uno.
Walter Mitty
44
"Segunda primaria" es un oxímoron. Tiene una clave primaria y puede tener claves secundarias.
Deja de dañar a Monica el
77
@RobbieDee hay razones válidas para no tener una base de datos completamente normalizada. Y tener un candidato o una clave secundaria no es exactamente duplicar datos.
Machado

Respuestas:

0

Puede agregar una columna UUID pero realmente no necesita (y no debería). Esta es una preocupación de la capa de presentación. No soñaría con decir, almacenar un valor de moneda de $ 1,999 y 1999.

Solo desea oscurecer el valor sobre la marcha para la aplicación. Puede hacer esto en la propia aplicación o como una vista de base de datos.

Como solo estamos hablando de un valor único, tal vez mire el cifrado de 2 vías, como AES o similar, cuanto más liviano, mejor.

El hash podría ser otra posibilidad: depende de si desea recuperar el número de factura, ya que el hash es una forma.

Robbie Dee
fuente
48

Tener una "clave primaria alternativa" es un concepto bien conocido en el modelado de bases de datos relacionales, se llama "clave alternativa" o, a veces, también "clave secundaria". El conjunto de "claves primarias potenciales" se denomina "claves candidatas". Ver https://beginnersbook.com/2015/04/alternate-key-in-dbms/

La forma en que implemente esto depende completamente de usted, especialmente si desea ocultar el número total de registros. No hay una "mejor manera", debe verificar sus requisitos, como el juego de caracteres permitido o útil, la longitud máxima, si desea que las ID distingan entre mayúsculas y minúsculas, si desea que sean legibles en una factura impresa, si alguien debe poder respetarlos en el teléfono sin errores, etc.

Doc Brown
fuente
11
También he visto los términos Clave natural frente a Clave sustituto utilizados para describir este escenario.
DanK
2
@Dari: preguntaste "cómo se llama esta técnica", en negrita. Y si el descifrado AES, tal vez sobre la marcha, produce claves del tipo que está buscando, úselas, eso no contradice mi respuesta.
Doc Brown
1
@Dari Porque agrega una sobrecarga completamente innecesaria a tu aplicación
Lamak
1
@RobbieDee Ya entendimos que no te gustan las teclas alternativas, pero eso no significa que sean inútiles. Me gusta el enfoque guid porque simplifica muchos problemas.
T. Sar - Restablece a Mónica el
1
@RobbieDee No usamos SQL Server. Usamos MySql. Y sucede porque alguien creará algo en Prod, digamos con ID 1234. En Dev, naturalmente, creamos muchas más entidades que en Prod. 1234 fue tomado hace mucho tiempo por alguna entidad desechable para pruebas. Cuando tenemos que probar una entidad desde prod, tenemos que migrarla de regreso a Dev, y su clave principal ya está en uso. La migración es mucho más fácil si las referencias a esa entidad están basadas en guid. Pero la hibernación funciona mucho mejor con una clave primaria que es int o long, por lo que la conservamos. Mis desarrolladores no son vagos o ignorantes, están experimentados.
corsiKa
9

La mayoría de las facturas tienen un número de factura, que según la mayoría de las reglas de contabilidad debe ser secuencial o un contador puede no firmar los resultados del año o el IRS (o similar en su país) puede querer hacer una auditoría completa de sus pestañas.

Un usuario podría deducir del número de factura cuántos clientes ha atendido, o cuánto tiempo pasó antes de que cambiara la estrategia de numeración en las facturas.

La cantidad de facturas almacenadas en la base de datos no es una medida del total general de sus facturas. Hay otros medios para averiguarlo, incluida la solicitud de sus informes anuales de la Cámara de Comercio.

Sin embargo, bloquearía la factura detrás de una pantalla de inicio de sesión de usuario, para que no todos puedan solicitarla. Luego, en el inicio de sesión del usuario, pueden usar una metodología ajax para solicitar sus facturas pendientes, etc. Esto asegura sus datos, oculta la URL por ajax (generalmente nadie puede molestarse en ver los detalles de cómo se construye la solicitud ajax) , y usted controla cómo se muestran y ofrecen los datos.

Tschallacka
fuente
77
Una estrategia común utilizada en la banca (con números de cheque) es no comenzar el recuento incremental en 1 sino más bien un número mayor por este motivo exacto.
DanK
Creo que es por eso que la identificación debe ser una clave primaria adicional, no un reemplazo de la clave primaria anterior.
Alexander
1
No lo llamaría una clave primaria. Iría por una babosa, un UUID como nombre, pero en esencia es solo otro campo indexado en la tabla. Id. De cotización, número de factura, lo que sea. Es un campo, pero no una clave principal. Una clave principal debe ser única y puede usarse internamente para el mapeo relacional. Si el campo está indexado, se puede buscar rápidamente mediante una consulta where. userXveryY.where ('número de factura', 'foobarbaz10'). get ();
Tschallacka
1
Está respondiendo una pregunta técnica con el argumento de que no es necesaria debido a las peculiaridades de los EE. UU. (Números de factura secuenciales requeridos, informes en la Cámara de Comercio). En mi opinión, esto no responde bien a la pregunta.
RemcoGerlich
7

Es posible que pueda usar hashids para esto, está diseñado para resolver exactamente este escenario.

Codificará su ID de base de datos en un hash corto (similar a la URL de un video de YouTube), y no requerirá que agregue ninguna clave secundaria a su tabla.

mitchdav
fuente
2
El nombre es algo engañoso, ya que no es hash, sino una función reversible. Pero parece ser la solución perfecta al problema.
Crazy Yoghurt
2
@CrazyYoghurt Cierto ... abordaron la razón para nombrarlo como lo hicieron aquí: hashids.org/#why-hashids
Eric King
3

Puede crear otra clave única, pero no debería. No por la razón dada. Hay formas más simples de ocultar los tamaños de las mesas.

El almacenamiento N_8Zk241vNacuesta 12 bytes por fila en la tabla e incluso más en el índice. Eso es bastante derrochador para lo que necesitas.

Cifrar el número entero idno le cuesta espacio y casi nada en el tiempo de ejecución. Cómo lo haga depende de su lenguaje de programación y / o su base de datos.

Tenga en cuenta que con AES obtiene un número entero de 128 bits, lo que significa 22 caracteres en base64, probablemente más de lo que desea. Un cifrado con un tamaño de bloque de 64 como DES o 3DES le proporciona 11 caracteres, tal como lo desea.

Use diferentes claves para diferentes tablas.

Si todo lo que necesita es ocultar los tamaños de las tablas, puede usar una secuencia común para todas las tablas. Tenga en cuenta que puede ser un cuello de botella si hay inserciones frecuentes en muchas de sus tablas. Con algo como Hibernate y un algoritmo Hi-Lo, este problema desaparece.

maaartinus
fuente
Exactamente: almacenar este valor solo para ocultar otro es simplemente incorrecto.
Robbie Dee
Esto puede funcionar en este escenario, ya que una ID de factura no es realmente confidencial, pero como regla general el uso de ID confidenciales ya que la estructura relacional en una base de datos causará un dolor de cabeza real si necesita enmascarar datos en algún momento en el futuro. Es mejor tratarlos como un atributo.
DanK
¿Cómo puedo aplicar aes aquí?
Dari
@Dari ¿Cómo puedes aplicar AES a cualquier cosa ? Sin saber su idioma, nadie puede decirlo. Por lo general, AES funciona con un byte[], puede escribir su iden cuatro u ocho bytes, agregar un número de tabla único y cifrar (la entrada debe ser exactamente 16 bytes). Si hay modos para elegir, el BCE tiene razón.
maaartinus
@DanK ¿Qué? ¿Estás afirmando que AES es inseguro? Sin conocer la clave, no hay nada que el atacante pueda hacer mejor que un atributo almacenado. Nada. +++ Supongo que no entiendo tu comentario.
maaartinus
0

En mi humilde opinión, la creación de dos claves principales diferentes no es posible. Por supuesto, puede poner ese uuid en una base de datos para tenerlo como "alias" para la clave primaria actual. Puede colocar un índice sobre esa columna con una restricción única, pero la clave primaria es (desde su esencia) única dentro de una sola tabla. Puede haber una clave primaria compuesta, pero eso no es lo que está buscando.

Así que sugiero ponerlo allí, pero tenerlo solo con índice. Puede crear un componente de manejo para consultar datos por PK, así como otra columna única. Cuando maneje la solicitud de "/ facturas / ..." simplemente verifique el parámetro; si es entero, busque el ID, de lo contrario, busque uuid. O puede tener la búsqueda uuid como alternativa cuando la búsqueda de ID no encontró nada.

Y sobre la generación de algunos uuids "aleatorios": ¿Por qué no algo como "tomar ID, agregar CONSTANT, convertir a hexadecimal". La iniquidad de la ID proporcionará la unicidad del líquido, el número hexadecimal es más difícil de leer para los mortales normales + agregar constante evitará tener un líquido como 00000001.

Jarda
fuente
1
"Por qué no algo así como" tomar ID, agregar CONSTANTE, convertir a hexadecimal ", porque eso es bastante fácil de resolver, dame una URL y veré todas las demás facturas en el sistema. OMI no hay problema en realidad, esto que resuelve, sólo los que potencialmente crea.
CompuChip
" Al manejar la solicitud de" / facturas / ... "simplemente verifique el parámetro - si es un número entero, busque la ID , de lo contrario busque uuid " El punto completo (según tengo entendido la pregunta) es evitar que alguien busque por ID ( /invoices/123, /invoices/124, ...) para que solo busque por UUID desde la URL.
TripeHound
Además, no todos los números hexadecimales contienen letras. Sería imposible distinguir siempre entre sus enteros subyacentes y sus números hexadecimales generados.
TRiG
@CompuChip como espero, te interesan las computadoras :-) para que reconozcas el número hexadecimal a primera vista. Pero la Q fue escrita de manera que no muestre el número de factura directamente para que otros sepan cuántas facturas hay. Cuando muestro algún número hexadecimal a mi esposa, madre, vecina ... no sabrán qué es ese "texto extraño". Si habrá un aviso sobre un problema de seguridad de acuerdo con los números de factura dentro de la Q, entonces sugeriría algún método de hash complejo para ese propósito.
Jarda
@TripeHound todavía podría buscar por ID internamente o en algún punto de entrada con acceso restringido ...
Jarda
0

Si ambas teclas apuntan al mismo hecho, y nunca chocarían. ¿Por qué no deriva la otra clave de la original utilizando alguna función escalar que crearía un código hash personalizado de su clave original?

alternativamente, puede crear una tabla de mapeo anexo, que almacenaría ambas versiones de la clave. esta tabla actuará como un diccionario para buscar la clave secundaria.

Según tengo entendido, las claves son índices implícitos, y cuanto más agregue índices, las inserciones más lentas serán.

A.Rashad
fuente
+1 Sí, agregar lo que es potencialmente una columna de cadena grande con un índice ciertamente no es la operación libre de valor que otros sugieren. Dejando de lado la sobrecarga de almacenamiento, a medida que se agregan índices, la velocidad de inserción comienza a degradarse.
Robbie Dee
0

Otro enfoque para su caso de uso particular es que, en lugar de modificar la base de datos y la aplicación, puede crear una ruta personalizada a las facturas para que / invoices /: f (id) donde f (id) sea alguna función de la identificación.

La ruta personalizada es responsable de asignar una solicitud a la acción correcta del lado del servidor.


fuente
0

Es una práctica totalmente aceptable, también llamada 'Clave alternativa' (AK). Básicamente, el AK es otro índice único o restricción única.

Incluso puede crear restricciones de clave externa basadas en su AK.

Un posible caso de uso es como lo que explicó: tiene un PK agrupado en un número de identidad cada vez mayor, pero no desea que este número se muestre o use como criterio de búsqueda, porque simplemente se puede adivinar. Entonces, además, tiene un identificador único aleatorio o un número de referencia como AK, y esa es la identificación que presenta al usuario

Alex Schievink
fuente
0

Hay varios tipos de claves / índices. Una clave principal es un índice único especial, y como dicen las respuestas, ciertamente puede crear otra clave única. Y estoy de acuerdo en que es mejor no exponer los elementos internos de su base de datos a menos que haya una muy buena razón.

Dado que la pregunta está en el contexto de las facturas y los números, podría valer la pena investigar cómo la industria contable espera que se vean los números de las facturas: http://smallbusiness.chron.com/assign-invoice-numbers-52422.html

Puede parecer complicado tener una identificación interna que sea una clave principal y otro campo único con el número de factura visible de la aplicación / cliente. Pero no es tan impuro cuando, digamos un año después, el cliente quiere adoptar un nuevo esquema de numeración de facturas. En ese caso, no alteraría la identificación interna y sus relaciones en otras tablas para volver a numerar toda la bola de cera. Mantendría su identificación interna tal como está y volvería a numerar el número de factura no interna.

Lo ideal es que intentes no vincular tablas en claves / claves externas que puedan cambiar, y mantener tus tablas y relaciones internas transparentes para la capa de la aplicación.

Thomas Carlisle
fuente
0

Ve a por ello.

Esto no es diferente de un campo "babosa" que los artículos de blog y similares a menudo tienen: una forma única de referirse al registro de la base de datos separado de la clave primaria, apto para su uso en una URL. Nunca escuché a nadie discutir contra ellos.

RemcoGerlich
fuente