2012-10-30 15 views
50

Ho creato un'applicazione in Rails su Heroku utilizzando un database PostgreSQL.UUID come chiave primaria in PostgreSQL fornisce prestazioni di indice scadenti?

Ha un paio di tabelle progettate per essere in grado di sincronizzare con dispositivi mobili in cui i dati possono essere creati in luoghi diversi. Perciò ho un campo uuid che è una stringa che memorizza un GUID oltre a una chiave primaria di incremento automatico. L'uuid è quello che viene comunicato tra il server e i client.

Mi sono reso conto dopo l'implementazione del motore di sincronizzazione sul lato server che questo porta a problemi di prestazioni quando è necessario mappare tra uuid < -> id tutto il tempo (durante la scrittura di oggetti, ho bisogno di interrogare per l'uuid per ottenere l'id prima di salvare e il contrario quando si inviano i dati indietro).

Ora sto pensando di passare a utilizzare UUID come chiave primaria rendendo la scrittura e la lettura molto più semplice e veloce.

Ho letto che UUID come chiave primaria a volte può fornire prestazioni di indice scadenti (frammentazione dell'indice) quando si utilizza l'indice della chiave primaria in cluster. PostgreSQL soffre di questo problema o è corretto utilizzare UUID come chiave primaria?

Ho già una colonna UUID oggi, quindi, per quanto riguarda l'archiviazione, sarà meglio perché rilasciare la colonna ID normale.

+2

Il campo 'id' utilizzato come chiave esterna da qualsiasi altra relazione nel database? Stai mantenendo questo campo 'id' perché ritieni che la PRIMARY KEY debba essere di tipo seriale per i motivi che hai descritto? –

+0

Il clustering con chiave primaria sintetica è solo un vantaggio se si dispone di un percorso di accesso frequente che desidera interrogare un intervallo di questi valori di chiave, che è piuttosto raro nel mondo reale. UUID è un tipo perfettamente fine per chiave primaria, è abbastanza compatto (16 byte) e più veloce in confronto op rispetto al tipo di testo. – dbenhur

+0

@Joshua I campi id vengono utilizzati come chiavi esterne, i campi UUID vengono utilizzati solo come campi regolari utilizzati per referenziare le relazioni durante la comunicazione (questa è la necessità di tradurli sempre tra loro) – thejaz

risposta

55

(io lavoro su Heroku Postgres)

Usiamo UUID come chiavi primarie su alcuni sistemi e funziona benissimo.

vi consiglio di utilizzare l'estensione uuid-ossp, e hanno anche Postgres generare UUID per voi:

heroku pg:psql 
psql (9.1.4, server 9.1.6) 
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) 
Type "help" for help. 

dcvgo3fvfmbl44=> CREATE EXTENSION "uuid-ossp"; 
CREATE EXTENSION 
dcvgo3fvfmbl44=> CREATE TABLE test (id uuid primary key default uuid_generate_v4(), name text); 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "test_pkey" for table "test" 
CREATE TABLE 
dcvgo3fvfmbl44=> \d test 
       Table "public.test" 
Column | Type |    Modifiers    
--------+------+------------------------------------- 
id  | uuid | not null default uuid_generate_v4() name | text | 
Indexes: 
    "test_pkey" PRIMARY KEY, btree (id) 

dcvgo3fvfmbl44=> insert into test (name) values ('hgmnz'); 
INSERT 0 1 
dcvgo3fvfmbl44=> select * from test; 
        id     | name 
--------------------------------------+------- 
e535d271-91be-4291-832f-f7883a2d374f | hgmnz 
(1 row) 

implicazioni sulle prestazioni EDIT

Sarà sempre dipenderà dal vostro carico di lavoro.

La chiave primaria intera ha il vantaggio della località in cui i dati simili si trovano più vicini. Ciò può essere utile ad esempio: query di tipo intervallo come WHERE id between 1 and 10000 sebbene il conflitto di blocco sia peggiore.

Se il carico di lavoro letto è totalmente casuale in quanto si effettuano sempre ricerche di chiavi primarie, non ci dovrebbe essere alcun degrado delle prestazioni misurabile: si paga solo per il tipo di dati più grande.

Scrivi molto su questo tavolo e questo tavolo è molto grande? È possibile, anche se non ho misurato questo, che ci sono implicazioni nel mantenere quell'indice. Per molti set di dati, gli UUID funzionano bene e utilizzare gli UUID come identificatori ha alcune proprietà interessanti.

Infine, potrei non essere la persona più qualificata per discutere o dare consigli su questo, in quanto non ho mai eseguito un tavolo abbastanza grande con un PK UUID in cui è diventato un problema. YMMV. (Detto questo, mi piacerebbe sentire delle persone che si imbattono in problemi con l'approccio!)

+0

Grazie per la risposta. Sto creando gli UUID nei modelli Rails oggi, è così buono come usare la funzione di database sopra? – thejaz

+0

Sì, non vedo alcun problema finché i vostri modelli di guide sono l'unica cosa che inserisce dati nel vostro database. – hgmnz

+0

@hgmnz: come si definisce la colonna id come uuid tramite una migrazione di Rails? –

1

Come indica la risposta accettata, le query di intervallo potrebbero essere lente in questo caso, ma non solo su id.

Autoincrement è naturalmente ordinato per data, quindi quando viene utilizzato l'autoincremento i dati vengono memorizzati cronologicamente su disco (vedi B-Tree) che velocizza le letture (nessuna ricerca di HDD).Ad esempio, se si elencano tutti gli utenti, l'ordine naturale verrebbe creato per data, che è lo stesso dell'autoincremento e quindi le query di intervallo vengono eseguite più velocemente su HDD mentre su SSD, suppongo, la differenza sarebbe inesistente dal momento che gli SSD sono di progettazione sempre casuale accesso (senza ricerca di teste, senza parti meccaniche coinvolte, solo elettricità pura)

Problemi correlati