2009-06-29 29 views
9

Sto pianificando un database per memorizzare molto testo. (post di blog, articoli di notizie, ecc.) Il database deve avere il titolo, il contenuto (max 50 caratteri al massimo), la data, il link e i campi della lingua. Lo stesso contenuto non può verificarsi su un link. I vecchi contenuti (più vecchi di 30 giorni, ad esempio) verranno eliminati.PostgreSQL: definizione di una chiave primaria su un database di grandi dimensioni

Ora, il problema è la chiave primaria. Potrei semplicemente impostare un campo di incremento automatico (tipo SERIAL) e usarlo come chiave primaria. Ma sembra stupido e uno spreco di spazio su disco, perché il campo non servirebbe a nessuno scopo ma essere una chiave primaria. (e il campo potrebbe esaurirsi, o no?) E c'è sempre un altro problema di prestazioni: il contenuto di ogni nuova riga inserita deve essere controllato per i duplicati. Quindi l'altra soluzione per la chiave primaria che ho trovato sarebbe quella di calcolare un hash sha256 di contenuto + valore di collegamento e quindi metterlo in una nuova colonna "hash" e usarlo come chiave primaria. Due piccioni con una fava. Naturalmente, il problema con questo sono le collisioni hash. È una grande minaccia?

Non ho alcuna esperienza con PostgreSQL e poca esperienza con i DBMS in generale, quindi apprezzerei un secondo parere prima di creare un database con le caratteristiche di prestazione di una chiocciola sull'autostrada (confronto orribile).

Per favore aiutatemi qui se avete qualche esperienza con database di grandi dimensioni. L'impostazione di una stringa di 64 caratteri come campo chiave primaria è una buona idea nella mia situazione? (Perché io sono sotto l'impressione che in genere questo è evitato)

risposta

9

appena fatto questo test esatto di DB piuttosto medio-grande (200 GB +), bigserial vinto con un margine abbastanza grande. Era più veloce da generare, più veloce da unire, meno codice, più piccolo ingombro. A causa del modo in cui Postgres lo memorizza, un bigint è trascurabile rispetto a un normale int. Lo spazio di archiviazione si esaurirà molto prima che tu debba preoccuparti di traboccare il bigint. Dopo aver eseguito l'hash computato contro il bigint, sostituisci il bigint fino in fondo.

+0

I test includevano "l'altro problema di prestazioni: il contenuto di ogni nuova riga inserita deve essere [sic] da verificare per i duplicati"? – onedaywhen

2

Alcuni suggerimenti:

  • L'archiviazione su disco di un intero primaria-chiave a 64 bit è trascurabile, non importa quanto il contenuto che avete.
  • Non scontrerai mai SHA256 e utilizzarlo come ID univoco non è una cattiva idea.

Una cosa bella del metodo di hash è che non si dispone di una singola sequenza di origine per generare nuove chiavi primarie. Questo può essere utile se il tuo database deve essere segmentato in qualche modo (ad esempio la distribuzione geografica) per il futuro ridimensionamento, poiché non devi preoccuparti delle collisioni o di un singolo punto di errore che genera sequenze.

Dal punto di vista della codifica, disporre di una singola chiave primaria può essere fondamentale per partecipare a tabelle di dati aggiuntive che è possibile aggiungere in futuro. Consiglio vivamente di usarne uno. Ci sono vantaggi per entrambi gli approcci proposti, ma il metodo di hash potrebbe essere il preferito, solo perché i valori di autoincremento/sequenza possono talvolta causare problemi di scalabilità.

+1

Se si utilizza SHA256 come chiave primaria, non deve essere immutabile? Cosa succede se il contenuto + il valore del link cambia? –

+0

Harvey, buon punto, ma se si volesse modificare il valore del contenuto di una riga, verificherei se esiste un hash del nuovo contenuto + link alredy. Se è così, nessun cambiamento potrebbe accadere. – KRTac

+0

Quindi, se il contenuto cambia, crei un nuovo record? –

1

Gli hash sono idee sbagliate per le chiavi primarie. Fanno finire gli inserti in ordine casuale nella tabella, e questo diventa molto costoso in quanto le cose devono essere riassegnate (anche se Postgres in realtà non lo applica come gli altri). Suggerisco una chiave primaria sequenziale che può essere un timestamp/timestamp a grana fine con il seguente numero sequenziale, che consente di uccidere due piccioni con una pietra e un secondo indice univoco contenente i codici hash. Tenere presente che si desidera mantenere la chiave primaria come una colonna più piccola (64 bit o meno).

Vedere la tabella http://en.wikipedia.org/wiki/Birthday_attack#The_mathematics in modo da poter essere sicuri che non si verificherà una collisione.

Non dimenticarti di aspirare.

3

Dovresti avere un sacco di record prima che il numero intero della tua chiave principale si esaurisca.

Il numero intero sarà più veloce per i join rispetto a una chiave primaria a 64 caratteri.Inoltre è molto più facile per le persone che scrivono le domande da affrontare.

Se una collisione è sempre possibile, non è possibile utilizzare l'hash come chiave primaria. Le chiavi primarie devono essere contrassegnate per essere univoche per definizione.

Ho visto centinaia di database di produzione per diverse società e enti governativi e non uno ha utilizzato una chiave primaria hash. Pensi che ci possa essere una ragione?

Ma, sembra stupido e uno spreco di spazio su disco, perché il campo non servirebbe a nessuno scopo ma a essere una chiave primaria.

Poiché una chiave primaria sostitutiva dovrebbe sempre essere priva di significato tranne che come chiave primaria, non sono sicuro quale sarebbe la tua obiezione.

+0

Sto pianificando di avere un sacco di righe nella tabella. Le vecchie righe verranno cancellate, ma il campo continuerà ad incrementare automaticamente il conteggio delle righe, quindi quando il campo seriale raggiunge 2147483647 non riesco a ottenere altre righe nella tabella, anche se il tavolo potrebbe essere mezzo vuoto. – KRTac

+1

Ti stai riferendo a un intero con segno a 32 bit. Per un intero con segno a 64 bit, il valore massimo è 9.223.372.036.854.775,807. Dubito che lo esauriresti mai. –

+1

Sarebbe più veloce di un hash, anche se è int per 64 bit? – KRTac

3

Vorrei scegliere di utilizzare una chiave surrogata, vale a dire. una chiave che non fa parte dei dati aziendali della tua applicazione. I requisiti di spazio aggiuntivi di un numero intero a 64 bit aggiuntivo quando si ha a che fare con fino a 50 kilobyte di testo per record sono trascurabili. Utilizzerai lo spazio in meno di in meno di quando inizi a utilizzare questa chiave come chiave esterna in altre tabelle.

L'utilizzo di un hash dei dati memorizzati in un record è un candidato molto negativo per una chiave primaria, nel caso in cui i dati su cui si basa l'hash cambino. Avrai quindi modificato anche la chiave primaria, con conseguente aggiornamento in tutto il luogo se hai relazioni da altre tabelle a questa.

PS. Una domanda simile è stata posta e risposta qui before.

Ecco un altro bel write-up sul tema: http://www.agiledata.org/essays/keys.html

+0

Ottimo consiglio, e sono d'accordo con la maggior parte di esso. Ma, come ho detto prima, cosa succede quando la chiave surogat raggiunge 2147483647? Potrei usare Bigserial, ma qual è il rendimento in questo? – KRTac

+0

In questo contesto (la memorizzazione di post di blog e articoli di notizie) dubito che raggiungere 2^31 articoli sarebbe molto probabile. Anche così, se si vuole pianificare in anticipo e giocare sul sicuro e utilizzare bigserial, direi che il risultato della perfomance sarà minimo, soprattutto se paragonato all'utilizzo di un CHAR (32) come PK. –

1

Vorrei utilizzare un numero intero a 32 bit come chiave primaria. Non credo che supererete molto presto quel numero :-) L'intera Wikipedia ha circa 3,5 milioni di articoli ... Se scriveste 1000 articoli al giorno ci vorrebbero quasi 6000 anni per raggiungere il massimo del tipo intero.

Problemi correlati