Mysql
 sql >> Database >  >> RDS >> Mysql

Come sostituire la chiave primaria di Django con un numero intero diverso che è univoco per quella tabella

L'idea

Ti consiglierei lo stesso approccio utilizzato da Instagram . Le loro esigenze sembrano seguire da vicino le tue.

Gli ID generati dovrebbero essere ordinabili in base al tempo (quindi un elenco di ID foto, ad esempio, potrebbe essere ordinato senza recuperare ulteriori informazioni sulle foto) Gli ID dovrebbero idealmente essere 64 bit (per indici più piccoli e una migliore archiviazione in sistemi come Redis) Il sistema dovrebbe essere introdotto come poche nuove "parti mobili" possibili:gran parte del modo in cui siamo stati in grado di scalare Instagram con pochissimi ingegneri è stata la scelta di soluzioni semplici e di facile comprensione di cui ci fidiamo.

Hanno inventato un sistema che ha 41 bit basati sul timestamp, 13 o lo shard del database e 10 per una porzione di incremento automatico. Dal momento che non sembra che tu stia usando frammenti. Puoi solo avere 41 bit per un copmonente basato sul tempo e 23 bit scelti a caso. Ciò produce una possibilità estremamente improbabile di 1 su 8,3 milioni di ottenere un conflitto se si inseriscono record contemporaneamente. Ma in pratica non è mai probabile che lo colpisca. Allora che ne dici di un po' di codice:

Generazione ID

START_TIME = a constant that represents a unix timestamp

def make_id():
    '''
    inspired by http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram
        '''
    
    t = int(time.time()*1000) - START_TIME
    u = random.SystemRandom().getrandbits(23)
    id = (t << 23 ) | u
    
    return id


def reverse_id(id):
    t  = id >> 23
    return t + START_TIME 

Nota, START_TIME nel codice sopra c'è un tempo di inizio arbitrario. Puoi usare time.time()*1000 , ottenere il valore e impostarlo come START_TIME

Nota che il reverse_id il metodo che ho pubblicato ti consente di scoprire a che ora è stato creato il record. Se hai bisogno di tenere traccia di tali informazioni, puoi farlo senza dover aggiungere un altro campo! Quindi la tua chiave principale sta effettivamente salvando lo spazio di archiviazione anziché aumentarlo!

Il modello

Ecco come sarebbe il tuo modello.

class MyClass(models.Model):
   id = models.BigIntegerField(default = fields.make_id, primary_key=True)  

Se apporti modifiche al tuo database al di fuori di django, dovresti creare l'equivalente di make_id come una funzione sql

Come nota a piè di pagina. Questo è un po' come l'approccio utilizzato da Mongodb per generare il suo _ID per ogni oggetto.