Dovrei investire il tempo per cambiare il tipo di colonna da CHAR (36) a UUID?


14

Ho già qualche milione di righe nel mio database. Non sapevo del tipo di dati UUID PostgreSQL quando ho progettato il mio schema.

Una delle tabelle ha 16 milioni di righe (da circa 3,5 a 4 milioni di record per frammento), con una crescita di circa 500.000 record al giorno. Ho ancora il lusso di abbattere il sistema di produzione per alcune ore, se necessario. Non avrò questo lusso tra una o due settimane.

La mia domanda è: varrà la pena farlo? Mi chiedo delle prestazioni JOIN, l'uso dello spazio su disco (il dump completo di gzip'd è 1,25 GiB), cose del genere.

Lo schema della tabella è:

# \d twitter_interactions
                Table "public.twitter_interactions"
         Column          |            Type             | Modifiers 
-------------------------+-----------------------------+-----------
 interaction_id          | character(36)               | not null
 status_text             | character varying(1024)     | not null
 screen_name             | character varying(40)       | not null
 twitter_user_id         | bigint                      | 
 replying_to_screen_name | character varying(40)       | 
 source                  | character varying(240)      | not null
 tweet_id                | bigint                      | not null
 created_at              | timestamp without time zone | not null
Indexes:
    "twitter_interactions_pkey" PRIMARY KEY, btree (interaction_id)
    "twitter_interactions_tweet_id_key" UNIQUE, btree (tweet_id)
    "index_twitter_interactions_on_created_at" btree (created_at)
    "index_twitter_interactions_on_screen_name" btree (screen_name)
Triggers:
    insert_twitter_interactions_trigger BEFORE INSERT ON twitter_interactions FOR EACH ROW EXECUTE PROCEDURE twitter_interactions_insert_trigger()
Number of child tables: 9 (Use \d+ to list them.)

Risposte:


13

Vorrei prendere in considerazione il passaggio al tipo UUID. char(36)richiede 40 byte, uuidrichiede 16, quindi risparmierai 24 byte per riga, che per te equivalgono a 12 MB al giorno, 4 GB dopo un anno. Più indici. A seconda dell'hardware che hai, non è molto, ma potrebbe essere. E si aggiunge se hai più opportunità di miglioramento come questo.

Inoltre, non vedo alcun vincolo nel tuo schema che assicuri che interaction_idsia effettivamente nel formato giusto. L'uso del giusto tipo ti darà anche quello.

Se ti piace questo, tuttavia, l'utilizzo di bigintfarebbe risparmiare ancora di più e avrebbe prestazioni ancora migliori. È molto improbabile che la tua applicazione sia così grande che una bigintcolonna per un ID non funzionerà.


Ho un sistema distribuito: più fonti di dati generano ID per le interazioni, quindi non posso usare un BIGINT semplice a meno che non riservassi N bit per l'ID nodo.
François Beausoleil,

3
@ FrançoisBeausoleil, riservare N bit per l'ID nodo equivale a utilizzare ogni numero N in una sequenza (e quindi facile da implementare). Inoltre, potresti prendere in considerazione l'utilizzo di chiavi composite.
Unreason,

1
Il coordinamento di più sequenze (con ID nodo) è in pratica una seccatura amministrativa e soggetta a errori umani. Non vedo alcun motivo per non utilizzare gli UUID in questo scenario, soprattutto perché i bit sono economici al giorno d'oggi (sia la memoria che l'archiviazione). In effetti, questo scenario è la vera ragione per cui gli UUID sono stati inventati decenni fa: condividere dati tra sistemi distribuiti senza coordinamento centralizzato .
Basil Bourque,

6

Non sono una persona di Postgres per nessuna parte dell'immaginazione, ma in base a ciò che so da SQL Server, più righe puoi inserire in una pagina di dati, migliori sono le prestazioni che otterrai (leggere i dati dal disco è in genere operazione più costosa). Pertanto, passare da un campo largo 36 ish a 1 byte a un GUID a 16 byte sembra un semplice risparmio sui costi. Meno letture si possono sostenere, più velocemente è possibile restituire risultati. Tutto ciò ovviamente presuppone che un GUID / UUID soddisfi le esigenze aziendali della tabella. Se un UUID lo soddisfa, sarebbe un bigint ? Ciò ridurrebbe ulteriormente lo spazio di archiviazione costa altri 8 byte per riga.

Modifica 1

Per i dati dei personaggi in Postgres, c'è un costo di archiviazione aggiuntivo per loro. Le stringhe brevi, sotto i 127 byte hanno un sovraccarico di 1 byte mentre qualcosa di più ha 4 byte, il che significa che il secondo rispondente ha ottenuto un costo di 40 byte per un campo di 36 byte. Ma c'è anche un'opzione per la compressione delle stringhe, quindi forse non costerà l'intero 40. Non posso dire quale sarebbe il costo finale, ma i fondamenti rimangono: qualsiasi cosa oltre 16 byte aumenterà il costo di archiviazione, impiegherà più tempo a leggere da e consuma più memoria.

Il requisito di archiviazione per una stringa breve (fino a 126 byte) è 1 byte più la stringa effettiva, che include il riempimento dello spazio in caso di carattere. Le stringhe più lunghe hanno 4 byte di sovraccarico invece di 1. Le stringhe lunghe vengono compresse automaticamente dal sistema, quindi il fabbisogno fisico sul disco potrebbe essere inferiore.


3

Oltre al problema di spazio, tieni presente che dovrai modificare ogni tabella per utilizzare il tipo di dati corretto, altrimenti le prestazioni del tuo join aumenteranno notevolmente.


Era un dato di fatto, ma grazie per avermelo ricordato.
François Beausoleil,

3
Quando faccio grandi cambiamenti come questo trovo che scrivere tutto (non importa quanto sia semplice ricordare la cosa) di solito paga.
mrdenny,

3

Oltre al risparmio in termini di dimensioni di dati e indici (come detto da altri), che si traduce in risparmi I / O, la cosa che devi considerare è come genererai nuovi valori interaction_ide quale sarà l'impatto sul indici e condizioni della query (join).

Per l'indice: sarà più piccolo, tuttavia se molte delle tue query utilizzano scansioni dell'indice il passaggio a UUID potrebbe rendere impossibili le scansioni dell'indice (a seconda di come genererai UUID) e bigintpotrebbe essere una scelta molto migliore.

Infine, poiché l'impatto delle prestazioni effettive dipende anche dai modelli di utilizzo e dalla distribuzione dei dati, è necessario eseguire test e disporre di un ambiente di sviluppo e test in cui è possibile testare le modifiche.

Questo ti darà una risposta molto più esatta sull'impatto sulle prestazioni.


Grazie per l'utile contributo e benvenuto nel sito :)
Jack dice di provare topanswers.xyz il

I miei schemi di accesso sono attraverso intervalli di date, JOINing utilizzando lo screen_name o tramite UUID. Non sono previste scansioni dell'intervallo sull'ID univoco. Grazie per la tua risposta, molto istruttiva.
François Beausoleil,
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.