GUID sequenziale o bigint per la tabella di database "enorme" PK


14

So che questo tipo di domanda emerge molto, ma devo ancora leggere qualsiasi argomento convincente per aiutarmi a prendere questa decisione. Per favore abbi pazienza!

Ho un enorme database: cresce di circa 10.000.000 di record al giorno. I dati sono relazionali e per motivi di prestazioni carico la tabella con BULK COPY. Per questo motivo, devo generare le chiavi per le righe e non posso fare affidamento su una colonna IDENTITY.

Un numero intero a 64 bit - un bigint - è abbastanza largo per me da usare, ma per garantire unicità, ho bisogno di un generatore centralizzato per creare i miei ID per me. Attualmente ho un tale servizio di generatore che consente a un servizio di riservare numeri di sequenza X e non garantisce collisioni. Tuttavia, una conseguenza di ciò è che tutti i servizi che ho sono dipendenti da questo unico generatore centralizzato, quindi sono limitato nel modo in cui posso distribuire il mio sistema e non sono contento delle altre dipendenze (come richiedere l'accesso alla rete) imposte con questo disegno. Questo è stato un problema in alcune occasioni.

Sto prendendo in considerazione l'utilizzo di GUID sequenziali come chiavi primarie (generate esternamente a SQL). Per quanto ho potuto constatare dai miei test, l'unico inconveniente è il sovraccarico di spazio su disco di un tipo di dati più ampio (che è esacerbato dal loro uso negli indici). Non ho assistito ad alcun rallentamento percepibile nelle prestazioni della query, rispetto all'alternativa bigint. Il caricamento della tabella con BULK COPY è leggermente più lento, ma non di molto. I miei indici basati su GUID non si stanno frammentando grazie all'implementazione GUID sequenziale.

Fondamentalmente, quello che voglio sapere è se ci sono altre considerazioni che potrei aver trascurato. Al momento, sono propenso a fare il salto e iniziare a utilizzare i GUID. Non sono affatto un esperto di database, quindi apprezzerei davvero ogni consiglio.


2
Come genereresti un "GUID sequenziale"?

È un'implementazione personalizzata. È fondamentalmente un formato di tipo GUID che ha 6 byte sostituiti con byte timestamp e 2 byte che rappresenta un numero di sequenza in cui il timestamp è lo stesso. Non è garantito che produca valori sequenziali perfetti, ma è abbastanza buono da rendere la frammentazione dell'indice un problema per me.

Stai quindi caricando questi dati da più fonti diverse? Suppongo anche che l'indice di cui ti preoccupi per frammentare sia l'indice cluster?

2
Se stai andando con un GUID sequenziale, dovresti guardare NEWSEQUENTIALID (). Dovrebbe fare quello che vuoi (aumentare monotonicamente) e non fare affidamento sul codice personalizzato.

2
Guarda il post di Jeremiah Peschka su Il problema con le chiavi Buona lettura e ha affrontato queste implementazioni molte volte.
Billinkc,

Risposte:


4

Sono in una situazione simile. Attualmente sto usando l'approccio GUID sequenziale e non ho frammentazione e facile generazione di chiavi.

Ho notato due svantaggi che mi hanno fatto iniziare la migrazione a bigint:

  1. Utilizzo dello spazio . 8 byte in più per indice. Moltiplicalo per circa 10 indici e otterrai un enorme spreco di spazio.
  2. Gli indici columnstore non supportano i GUID.

(2) Era l'assassino per me.

Ora genererò le mie chiavi in ​​questo modo:

yyMMddHH1234567890

Userò una data iniziale più l'ora e dopo avrò una parte sequenziale . Ciò mi consente di eseguire una query su intervallo dei miei dati per data senza alcun indice di addizione. Questo è un bel bonus per me.

Genererò la parte sequenziale del bigint usando un algoritmo HiLo che si presta bene alla distribuzione .

Spero che alcuni di questi siano trasferiti alla tua situazione. Consiglio vivamente di usare bigint.


1
Contrassegnando questa come "risposta", poiché è la soluzione migliore (e sembra che apprezzi ciò che ti sto chiedendo e perché questo non è così semplice come potrebbe apparire per la prima volta). Penso che andrò con un generatore di sequenze condivise (che funzionerà in modo simile al suggerimento dell'algoritmo HiLo). Ho questo lavoro su un altro sistema con pochi problemi, dovrò solo sopportare la dipendenza aggiuntiva. Oh bene. Grazie.
Barguast,

3

Con un tipo INT, a partire da 1, ottieni oltre 2 miliardi di righe possibili, che dovrebbero essere più che sufficienti per la stragrande maggioranza dei casi. Con BIGINT, ottieni circa 922 quadrilioni (922 con 15 zeri - 922'000 miliardi) - abbastanza per te ??

Se usi un INT IDENTITYinizio da 1 e inserisci una riga ogni secondo, hai bisogno di 66,5 anni prima di raggiungere il limite di 2 miliardi ....

Se usi un punto BIGINT IDENTITYiniziale a 1 e inserisci mille righe al secondo, hai bisogno di uno strabiliante 292 milioni di anni prima di raggiungere il limite di 922 quadrilioni ....

Usando i tuoi 10 milioni di righe al giorno, avrai abbastanza numeri per circa 1'844'674'407'370 giorni ( 1844 miliardi di giorni o un segno di spunta su 5 miliardi di anni ) di dati: è abbastanza buono per le tue esigenze ?

Maggiori informazioni (con tutte le opzioni disponibili) nella documentazione online di MSDN .


1
Il tasso di inserimento di 10 milioni di righe al giorno esaurirebbe l'intervallo INT in 200 giorni.
Mceda,

@mceda: si - ho rivendicato qualcos'altro? Non esaurisce la BIGINTgamma così rapidamente, però ....
marc_s,

Grazie, ma come ho detto nella mia domanda, ho bisogno degli ID prima che vengano inviati al database. I dati sono relazionali, quindi devo assegnare le chiavi primarie ed esterne prima che vengano copiate in blocco. Se non fosse per quello, un IDENTITY BIGINT sarebbe probabilmente perfetto.

2
@Barguast: non potresti semplicemente inserire in blocco i tuoi dati in una tabella di gestione temporanea (senza l'identità) e quindi spostarli da lì nelle tue tabelle di dati effettive utilizzando BIGINT IDENTITY?
marc_s,

@marc_s: sì, il calcolo fornito non era allineato alla domanda: "Se usi INT IDENTITY a partire da 1 e inserisci una riga ogni secondo, hai bisogno di 66,5 anni prima di raggiungere il limite di 2 miliardi".
mceda,

2

Ti consiglio di utilizzare SEQUENCE del tipo di dati BIGINT in SQL 2012 Questo è molto più flessibile di IDENTITY con opzioni come cache / nocache, puoi anche assegnare un intervallo di sequenza per l'operazione batch come sp_sequence_get_range.


Sfortunatamente, SEQUENCE non è supportato su SQL Azure.
Timothy Lee Russell

2

È la ragione per cui non puoi usare IDENTITY perché ci sono già relazioni di chiave esterna tra tabelle separate che stai caricando? E non esiste nessun'altra chiave naturale per essere in grado di collegarli in un'operazione da un'area di stadiazione all'area di produzione? Per questo motivo, vorrei sapere un po 'di più su come sono attualmente "collegati" nel sistema di origine prima di eseguire una copia bulk? I sistemi di origine multipla usano semplicemente le loro sequenze e hanno la possibilità di sequenze in conflitto quando vengono portati in un database condiviso?

L'ID COMB / GUID sequenziale è una tecnica con cui ho familiarità, ed è praticabile ogni volta che hai effettivamente bisogno di quell'unicità globale assegnata al di fuori del database - è effettivamente un'identità di riga utilizzabile sia all'interno che all'esterno del database. Per questo motivo, in ambienti altamente distribuiti o scenari disconnessi, è una scelta OK

Tranne se non ne hai davvero bisogno, perché quella differenza di larghezza extra è significativa quando la dimensione dei dati aumenta e queste chiavi sono in ogni indice e le serie di lavoro per molte query.

Inoltre, con la generazione distribuita, se le righe in realtà non rientrano nell'ordine della colonna GUID, i problemi con l'utilizzo di questo per la chiave di indice cluster (stretto, statico, crescente) potrebbero potenzialmente causare frammentazione rispetto al clustering su IDENTITY rimangono.


0

In generale è possibile utilizzare la OUTPUTclausola di INSERTcomando per inserire i dati in entrambe le tabelle e relativi al campo identità.

L'identificatore basato sul timestamp non deve essere considerato affidabile - dipende dall'orologio di sistema che a sua volta dipende da molte cose - dall'orologio hardware ai servizi di sincronizzazione dell'ora.

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.