Creazione di una chiave primaria secondaria in un database per alcune tabelle


22

Ad alcune delle mie tabelle voglio aggiungere "second_primary_key" che sarà uuid o una chiave lunga casuale. Ne ho bisogno perché per alcune tabelle non voglio esporre numeri interi alla mia applicazione web. Cioè, in una pagina "/ fatture" ho un elenco di fatture e un collegamento a "/ fatture /: id" dove: id è un numero intero. Non voglio che un utente sappia quante fatture nel mio sistema sono lì, quindi invece di "/ fatture / 123" Voglio usare il suo "secondo_primario_chiave" in modo che l'URL sarà "/ fatture / N_8Zk241vNa"

Lo stesso vale per altri tavoli in cui voglio nascondere il vero ID.

Mi chiedo, è una pratica comune? Qual è il modo migliore per implementarlo?

E come si chiama questa tecnica dopo tutto, in modo che io faccia una ricerca su di essa?


20
Perché non sbarazzarsi del numero intero?
Larsbe,

4
Puoi definire tutte le chiavi / indici univoci che desideri su una tabella.
abuzittin gillifirca,

2
Forse dovresti chiamarlo una chiave candidata secondaria. "Primario" suggerisce solo uno.
Walter Mitty,

4
Il "secondo primario" è un ossimoro. Hai una chiave primaria e puoi avere chiavi secondarie.
Smetti di fare del male a Monica il

7
@RobbieDee ci sono validi motivi per non avere un database completamente normalizzato. E avere un candidato o una chiave secondaria non sta esattamente duplicando i dati.
Machado,

Risposte:


0

È possibile aggiungere una colonna UUID, ma in realtà non è necessario (e non dovrebbe). Questa è una preoccupazione del livello di presentazione. Non ti aspetteresti di dire, memorizzando un valore in valuta di $ 1,999 e 1999.

Vuoi solo un modo per oscurare il valore al volo per l'applicazione. È possibile farlo nell'applicazione stessa o come vista del database.

Dato che stiamo parlando solo di un singolo valore, forse guarda la crittografia a 2 vie come AES o simile: più leggero è, meglio è.

L'hash potrebbe essere un'altra possibilità: dipende dal fatto che si desideri recuperare il numero di fattura, poiché l'hash è un modo.


48

Avere una "chiave primaria alternativa" è un concetto ben noto nella modellazione di database relazionali, si chiama "chiave alternativa", o talvolta anche "chiave secondaria". L'insieme di "potenziali chiavi primarie" si chiama "chiavi candidate". Vedi https://beginnersbook.com/2015/04/alternate-key-in-dbms/

Il modo in cui lo implementate dipende completamente da te, soprattutto se vuoi nascondere il numero totale di record. Non esiste un "modo migliore", è necessario verificare i propri requisiti come set di caratteri consentiti o utili, lunghezza massima, se si desidera che gli ID facciano distinzione tra maiuscole e minuscole, se si desidera che siano leggibili su una fattura stampata, se qualcuno deve essere in grado di rispedirli al telefono senza errori e così via.


11
Ho visto anche i termini chiave naturale vs surrogato chiave usati per descrivere questo scenario.
DanK,

2
@Dari: hai chiesto "come si chiama questa tecnica" - in grassetto. E se la decrittazione AES - forse al volo - produce chiavi del tipo che stai cercando, usale, ciò non contraddice la mia risposta.
Doc Brown,

1
@Dari Perché aggiunge un sovraccarico completamente inutile alla tua app
Lamak

1
@RobbieDee Abbiamo già capito che non ti piacciono i tasti alternativi, ma ciò non significa che siano inutili. Mi piace l'approccio guid perché semplifica molti problemi.
T. Sar - Ripristina Monica il

1
@RobbieDee Non utilizziamo SQL Server. Usiamo MySql. E succede perché qualcuno creerà qualcosa su Prod, diciamo con ID 1234. Su Dev, naturalmente, creiamo molte più entità di quante ne facciamo su prod. 1234 è stato preso molto tempo fa da qualche entità usa e getta per il test. Quando dobbiamo testare un'entità da prod, dobbiamo migrarla di nuovo su Dev - e la sua chiave primaria è già in uso. La migrazione è molto più semplice se i riferimenti a quell'entità sono basati su guid. Ma l'ibernazione funziona molto meglio con una chiave primaria che è int o long, quindi la manteniamo. I miei sviluppatori non sono pigri o ignoranti: sono esperti.
corsiKa

9

La maggior parte delle fatture ha un numero di fattura, che secondo la maggior parte delle regole di contabilità deve essere sequenziale o un contabile potrebbe non approvare i risultati dell'anno o l'IRS (o simile nel tuo paese) potrebbe voler effettuare un controllo completo nelle schede.

Un utente potrebbe dedurre dal numero di fattura quanti clienti hai servito o quanto tempo è trascorso prima di modificare la strategia di numerazione nelle fatture.

Quante fatture sono archiviate nel database non è una misura del totale complessivo delle fatture. Esistono altri mezzi per scoprirlo, inclusa la richiesta dei rapporti annuali alla Camera di commercio.

Vorrei, tuttavia, bloccare la fattura dietro una schermata di accesso dell'utente, quindi non tutti possono richiederla. Quindi, al login dell'utente, possono utilizzare una metodologia ajax per richiedere le loro fatture in sospeso, ecc. Questo protegge i tuoi dati, nasconde l'URL di ajax (di solito nessuno può preoccuparsi di guardare i dettagli di come viene costruita la richiesta ajax) e controlli il modo in cui i dati vengono visualizzati e offerti.


7
Una strategia comune utilizzata nel settore bancario (con numeri di controllo) non è quella di avviare il conteggio incrementale da 1 ma piuttosto un numero maggiore per questo motivo esatto.
DanK,

Penso che sia per questo che l'id deve essere una chiave primaria aggiuntiva, non una sostituzione della vecchia chiave primaria.
Alexander,

1
Non lo definirei una chiave primaria. Vorrei una lumaca, un UUID come nome, ma in sostanza è solo un altro campo indicizzato nella tabella. ID preventivo, numero fattura, qualunque. È un campo, ma non una chiave primaria. Una chiave primaria deve essere unica e può essere utilizzata internamente per la mappatura relazionale. Se il campo è indicizzato, può essere cercato rapidamente da una query where. userXveryY.where ( 'INVOICE_NUMBER', 'foobarbaz10') get ().;
Tschallacka,

1
Stai rispondendo a una domanda tecnica con una discussione secondo cui non è necessaria a causa delle peculiarità degli USA (numeri di fattura sequenziali richiesti, rapporti alla Camera di commercio). IMO questo non risponde bene alla domanda.
Remco Gerlich,

7

Potresti essere in grado di utilizzare hashidi per questo, è progettato per risolvere esattamente questo scenario.

Codificherà l'ID del tuo database in un hash breve (simile all'URL di un video di YouTube) e non ti richiederà di aggiungere chiavi secondarie al tuo tavolo.


2
Il nome è in qualche modo fuorviante, in quanto non è hash, ma funzione reversibile. Ma sembra essere la soluzione perfetta al problema.
Crazy Yoghurt,

2
@CrazyYoghurt Vero ... hanno affrontato il motivo della denominazione come hanno fatto qui: hashids.org/#why-hashids
Eric King,

3

Puoi creare un'altra chiave univoca, ma non dovresti. Non per il motivo indicato. Esistono modi più semplici per nascondere le dimensioni della tabella.

La memorizzazione N_8Zk241vNacosta 12 byte per riga nella tabella e ancora di più nell'indice. È piuttosto dispendioso per quello che ti serve.

La crittografia del numero intero idnon ti costa spazio e quasi nulla in fase di esecuzione. Come lo fai dipende dal tuo linguaggio di programmazione e / o dal tuo database.

Si noti che con AES si ottiene un numero intero a 128 bit, che significa 22 caratteri in base64, probabilmente più di quanto si desideri. Un codice con una dimensione di blocco di 64 come DES o 3DES ti dà 11 caratteri, proprio come vuoi tu.

Utilizzare chiavi diverse per tabelle diverse.

Se tutto ciò che serve è nascondere le dimensioni delle tabelle, è possibile utilizzare una sequenza comune per tutte le tabelle. Si noti che potrebbe essere un collo di bottiglia in caso di inserimenti frequenti in molte tabelle. Con qualcosa come Hibernate e un algoritmo Hi-Lo, questo problema scompare.


Esatto: memorizzare questo valore solo per nasconderne un altro è semplicemente sbagliato.
Robbie Dee,

Ciò può funzionare in questo scenario poiché un ID fattura non è realmente riservato, ma come regola generale l'uso di ID riservati in quanto la struttura relazionale in un database causerà un mal di testa reale se è necessario mascherare i dati in futuro. Meglio trattarli come un attributo.
DanK,

come posso applicare aes qui?
Dari,

@Dari Come puoi applicare AES a qualsiasi cosa ? Senza conoscere la tua lingua, nessuno può dirlo. Di solito, AES funziona con a byte[], puoi scrivere il tuo idin quattro o otto byte, aggiungere un numero di tabella univoco e crittografare (l'input deve essere esattamente di 16 byte). Se ci sono modalità tra cui scegliere, la BCE ha ragione.
maaartinus,

@ DanK Cosa? Stai sostenendo che AES non è sicuro? Senza conoscere la chiave, l'attaccante non può fare nulla di meglio che per un attributo memorizzato. Niente. +++ Suppongo che non capisco il tuo commento.
maaartinus,

0

Non è possibile creare due chiavi primarie diverse. Ovviamente puoi inserire quel uuid in un DB per averlo come "alias" per la chiave primaria corrente. Puoi mettere un indice sopra quella colonna con un vincolo univoco, ma la chiave primaria è (dalla sua essenza) una singola all'interno di una singola tabella. Può esserci una chiave primaria composita, ma non è quello che stai cercando.

Quindi suggerisco di metterlo lì, ma averlo solo con indice. È possibile creare un componente di gestione per l'interrogazione dei dati tramite PK e altre colonne univoche. Quando gestisci la richiesta per "/ fatture / ..." controlla solo il parametro - se è intero, cerca l'ID, altrimenti cerca il uuid. Oppure puoi avere la ricerca uuid come fallback quando la ricerca ID non ha trovato nulla.

E sulla generazione di alcuni uuidi "casuali": perché non qualcosa del tipo "prendi ID, aggiungi COSTANTE, converti in esadecimale". L'iniquità dell'ID fornirà l'unicità di uuido, il numero esadecimale è più difficile da leggere per i normali mortali + l'aggiunta di costanti eviterà di avere uuidi come 00000001.


1
"Perché non qualcosa del tipo" prendi ID, aggiungi COSTANTE, converti in esadecimale "- perché è abbastanza facile da capire - dammi un URL e darò un'occhiata a tutte le altre fatture nel sistema. IMO non ci sono problemi che questo risolve effettivamente, solo quelli che potenzialmente crea.
CompuChip

" Quando gestisci la richiesta per" / fatture / ... "controlla solo il parametro - se è intero, cerca l'ID , altrimenti cerca uuid " L'intero punto (come ho capito la domanda) è impedire a qualcuno di cercare tramite ID ( /invoices/123, /invoices/124, ...) in modo da cercare solo per UUID dall'URL.
TripeHound,

Inoltre, non tutti i numeri esadecimali contengono lettere. Sarebbe impossibile distinguere sempre tra numeri interi sottostanti e numeri esadecimali generati.
TRiG

@CompuChip come mi aspetto, sei interessato ai computer :-), quindi riconosci il numero esadecimale a prima vista. Ma la Q è stata scritta in modo da non mostrare direttamente il numero della fattura per far sapere agli altri quante fatture ci sono. Quando mostrerò un numero esadecimale a mia moglie, a mia madre, al mio vicino ... non sapranno cos'è quello "strano testo". Se ci saranno avvisi di problemi di sicurezza in base ai numeri di fattura all'interno della Q, suggerirei un metodo di hashing complesso a tale scopo.
Jarda,

@TripeHound potrebbe ancora essere in grado di cercare per ID internamente o all'interno di un punto di accesso con accesso limitato ...
Jarda,

0

Se entrambe le chiavi indicano lo stesso fatto e non si scontrerebbero mai. Perché non derivare l'altra chiave da quella originale usando una funzione scalare che creerebbe un codice hash personalizzato della tua chiave originale.

in alternativa, è possibile creare una tabella di mappatura degli allegati, che memorizzerà entrambe le versioni della chiave. questa tabella fungerà da dizionario per la ricerca della chiave secondaria.

Secondo la mia comprensione, le chiavi sono indici impliciti e più si aggiungono indici, più gli inserimenti saranno lenti.


+1 Sì, l'aggiunta di ciò che è potenzialmente una colonna di stringa di grandi dimensioni con un indice non è certamente l'operazione senza valore suggerita da altri. Spazio di archiviazione a parte, man mano che vengono aggiunti gli indici, la velocità di inserimento inizia a ridursi.
Robbie Dee,

0

Un altro approccio per il tuo particolare caso d'uso è che invece di modificare il database e l'applicazione, puoi semplicemente creare un percorso personalizzato verso le fatture in modo che / fatture /: f (id) dove f (id) sia una funzione dell'id.

Il percorso personalizzato è responsabile del mapping di una richiesta sul lato server dell'azione corretta.


0

È una pratica totalmente accettabile, chiamata anche 'Chiave alternativa' (AK). Fondamentalmente l'AK è un altro indice univoco o un vincolo unico.

Puoi persino creare vincoli di chiave esterna in base al tuo AK.

Un possibile caso d'uso è come quello che hai spiegato: hai un PK cluster su un numero di identità sempre crescente, ma non vuoi che questo numero venga visualizzato o utilizzato come criterio di ricerca, perché può essere semplicemente indovinato. Quindi, inoltre, hai un identificatore univoco casuale o un numero di riferimento come AK e questo è l'ID che presenti all'utente


0

Esistono diversi tipi di chiavi / indici. Una chiave primaria è un indice univoco speciale e, come dicono le risposte, puoi sicuramente creare un'altra chiave univoca. E sono d'accordo che è meglio non esporre gli interni del tuo database a meno che non ci sia una ragione molto buona.

Poiché la domanda è nel contesto di fatture e numeri, potrebbe essere utile ricercare come il settore della contabilità si aspetta che i numeri delle fatture appaiano: http://smallbusiness.chron.com/assign-invoice-numbers-52422.html

Può sembrare disordinato avere un ID interno che è una chiave primaria e un altro campo univoco con il numero di fattura visibile dell'applicazione / cliente. Ma non è così sporco quando, diciamo un anno dopo, il cliente vuole adottare un nuovo schema di numerazione delle fatture. In tal caso non dovresti disturbare l'id interno e le sue relazioni in altre tabelle per rinumerare l'intera sfera di cera. Manterresti il ​​tuo ID interno così com'è e re-numeri il numero di fattura non interna.

Idealmente, fai del tuo meglio per non legare tabelle su chiavi / chiavi esterne che potrebbero cambiare e mantenere le tue tabelle interne e le relazioni trasparenti al livello dell'app.


0

Fallo.

Questo non è dissimile da un campo "slug" che spesso hanno articoli di blog e simili - un modo unico per fare riferimento al record del database separato dalla chiave primaria, adatto per l'uso in un URL. Non ho mai sentito nessuno discutere contro quelli.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.