Molte colonne contro poche tabelle: le prestazioni sono sagge


12

Sì, sono consapevole che la normalizzazione dei dati dovrebbe essere la mia priorità (così com'è).

  1. Ho una tabella con 65 colonne memorizzazione dei dati del veicolo con le colonne: used_vehicle, color, doors, mileage, pricee così via, in totale 65.
  2. Ora, posso dividere che e hanno un Vehicletavolo, VehicleInterior, VehicleExterior, VehicleTechnical, VehicleExtra(tutti uno-a-uno con i principali Vehicletabella).

Supponiamo che avrò circa 5 milioni di file (veicoli).

Attivato SELECTcon una WHEREclausola: le prestazioni miglioreranno nella ricerca (entrambi i casi sono indicizzati almeno su IDs):

  1. Vehicle tavolo con 65 colonne o
  2. Vehicletabella con JOINSsu altre quattro tabelle (tutte con 5 milioni di righe) per restituire tutti i dati relativi a Vehicle?

(Come per il motore di database, considera PostgreSQL e / o MySQL).

Apprezzo davvero le informazioni dettagliate che potresti avere dalla tua esperienza precedente?


1
Uno dei motivi per cui (partizionamento verticale) è se hai query che trattano le colonne da VehicleInterior, altre query che trattano solo le colonne VehicleTechnical, ecc. O se ci sono molte file / veicoli che non hanno assolutamente informazioni su (ad esempio) VehicleExtraquindi invece di molte righe con molti null in una tabella, hai righe nel resto delle tabelle e nessuna riga inVehicleExtra
ypercubeᵀᴹ

Risposte:


14

Supponendo che stiamo parlando di relazioni 1: 1 tra tutte le tabelle.

Lo spazio di archiviazione complessivo è praticamente sempre (sostanzialmente) più economico con una singola tabella anziché con più tabelle nella relazione 1: 1. Ogni riga ha 28 byte di sovraccarico, più tipicamente qualche byte in più per il riempimento extra. E devi archiviare la colonna PK con ogni tabella. E avere un indice (ridondante) separato su ciascuna di queste colonne ... Le dimensioni contano per le prestazioni.

Questo è vero anche se molte colonne sono NULL nella maggior parte delle righe perché l' archiviazione NULL è molto economica :

Durante il recupero di tutte le colonne una singola tabella è sostanzialmente più veloce di 5 tabelle unite. È anche molto più semplice . Cinque tabelle possono essere difficili da unire se non tutte le righe sono presenti in tutte le tabelle. Con le WHEREcondizioni destinate a una singola tabella, è abbastanza facile aggiungere altre tabelle con LEFT JOIN. Non banale se hai predicati su più tabelle ...

Il partizionamento verticale può comunque migliorare le prestazioni di determinate query. Ad esempio, se il 90% delle tue query recupera le stesse 5 colonne delle 65 disponibili, ciò sarebbe più veloce se una tabella contenesse solo queste 5 colonne.

OTOH, potresti essere in grado di soddisfare tali query su alcune colonne selezionate con un indice "di copertura" che consente scansioni solo indice .

Un altro candidato per il partizionamento verticale: se hai molti aggiornamenti su poche colonne, mentre il resto non cambia quasi mai. In tal caso potrebbe essere molto più economico dividere le righe, poiché Postgres scrive una nuova versione di riga per ogni aggiornamento. Esistono eccezioni per i grandi valori memorizzati fuori linea ("TOASTed"). Più dettagli:

Dipende davvero dalla situazione completa. In caso di dubbio, scegli la semplice soluzione di avere un solo tavolo, soprattutto se ritrae bene la realtà: nel tuo esempio, quelli sono tutti attributi di un'auto e hanno un senso insieme.


gli aggiornamenti saranno rari se nessuno e seleziona saranno principalmente per tutte le colonne (pagina dei dettagli del veicolo) e le informazioni principali (poche colonne) per l'elenco dei risultati di ricerca, e in effetti forse la soluzione migliore sarebbe due tabelle: una con le informazioni principali (poche colonne ) e l'altra tabella con il resto delle colonne. quindi in questo caso qual è la tua opinione su join sql con diciamo 5 milioni di righe - per quanto riguarda le prestazioni? A proposito, grazie per il tuo sforzo dettagliato
Urim Kurtishi,

1
@octavius: una sola tabella con un indice a più colonne sulle poche colonne per consentire scansioni solo dell'indice per l'elenco dei risultati potrebbe essere il percorso migliore. (Tenere presente che la sequenza di colonne è importante negli indici btree .) I join non sono così costosi, ma saranno comunque più veloci senza join. Le dimensioni di archiviazione aggiunte e la diffusione dei dati per più tabelle potrebbero essere il rallentamento maggiore (più pagine di dati da leggere per ogni query).
Erwin Brandstetter,

1
Concordo con il commento di Erwins sul fatto che la risposta dipenderà davvero dalla situazione completa o dall'uso nel mondo reale. Se hai scoperto che il 90% delle query riguardava un piccolo sottoinsieme dei dati e le prestazioni erano assolutamente di primaria importanza, potrebbe esserci un motivo per giustificare lo sforzo supplementare suddiviso in molte tabelle. Personalmente proverei a mantenere semplice il modello di dati. Inoltre, quanto è veloce abbastanza veloce? Quanto sforzo fai per salvare l'ultimo millisecondo? Hai provato a deridere dati e fare dei test?
Sir Swears-a-lot

@ErwinBrandstetter hai menzionato nella tua risposta che le relazioni sono 1: 1. Che dire delle navi relazione 1: N?
Slim

Per una relazione 1: N sono comunque necessarie due tabelle separate. Tranne se si riempiono più righe in un array o un tipo di documento. Quindi dipende. I principi qui descritti si applicano indipendentemente. I tuoi modelli di accesso e le strategie di indice possono fare la differenza. Poni una nuova domanda se vuoi essere più specifico.
Erwin Brandstetter,

0

Una selezione su una singola tabella dovrebbe essere sempre più veloce. Non appena hai trovato il tuo veicolo hai già tutti i dettagli.

Tuttavia si perde l'efficienza della normalizzazione. Ad esempio, se 1 macchina avesse molti modelli con opzioni diverse.

È un db di riferimento di tutte le auto? O un elenco di veicoli usati? Ci sarebbero molti esempi della stessa marca / modello con le stesse opzioni?

Modifica: dovrei qualificare la mia risposta come rdbms generico piuttosto che postgres specifico. Rinvio alla risposta dettagliata di @Erwin specifica per Postgres


2
"Una selezione su una singola tabella dovrebbe essere sempre più veloce." Perché?
ypercubeᵀᴹ

modello di veicolo e modello di veicolo sono tabelle diverse, quindi la tabella del veicolo ha chiavi esterne di modello di veicolo e modello di veicolo. non penso che la normalizzazione sia un problema qui. capisco che selezionare su una singola tabella sarebbe più veloce, tuttavia abbiamo una situazione diversa, in che modo la riga con molte colonne influirà sulle prestazioni e così via rispetto alle tabelle con meno colonne (ma poche tabelle - 5 delle quali con join)
Urim Kurtishi

Mi dispiace di aver perso il punto che marca e modello erano già separati. La versione breve è che i join si impegnano per il motore di database. Se si utilizza una singola tabella / riga, si otterrà tutto in una sola selezione, il che comporterebbe una minore I / O e sovraccarico per il motore db.
Sir Swears-a-lot
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.