Progettazione di database: nuova tabella contro nuove colonne


38

(Questo è stato suggerito per essere ripubblicato qui da StackOverflow)

Attualmente ha una tabella .. e deve iniziare ad aggiungere nuove colonne di dati. Non tutti i record (anche andando avanti con nuovi dati dopo aver aggiunto le nuove colonne di dati) avranno dati. Quindi mi chiedo se questo è più adatto per una nuova tabella poiché è davvero un'estensione di alcune delle righe di dati e non applicabile a ogni riga.

In altre parole, poiché ci saranno molte colonne inutilizzate per quei nuovi elementi di dati, sembra che questo sarebbe più adatto per una nuova tabella?

La prima tabella è un record di visualizzazioni di pagina (attualmente 2 milioni di record)

- id
- Indirizzo IP
- volte visualizzate
- creato_ al timestamp
- Data

per ogni indirizzo IP, viene creato un record al giorno e le visualizzazioni di pagina consecutive vengono aggiunte alle visualizzazioni dei tempi al giorno

campi aggiuntivi sarebbero per il tracciamento del punto di origine (ad es. fonte / mezzo / campagna di analisi di google)

Non tutte le visite avranno tali informazioni. Suppongo che circa il 10% delle righe disporrà dei dati (dato che di solito viene attribuito solo alla prima visita)

L'uso principale dei dati sarebbe quello di attribuire la provenienza delle persone. Questo potrebbe finire per essere usato più frequentemente (che poi sembra prestarsi al singolo tavolo)

Apprezzo il feedback: puoi aggiungere altro se necessario

Risposte:


29

Ciò con cui stai lottando è il partizionamento verticale. Questa è una tecnica di progettazione di database fisici per migliorare le prestazioni. Come con qualsiasi tecnica di progettazione di database fisici, la sua applicabilità dipende dalle query specifiche che si sta tentando di ottimizzare e se questa tecnica le ottimizzerà. Da un punto di vista logico, se questi nuovi campi dipendono dalla chiave candidata per la tua entità, allora sono fatti su di essa che appartengono ad essa. Per prima cosa dovresti assicurarti di comprendere appieno la dipendenza funzionale di questi nuovi campi dalle tue chiavi candidate per verificare che siano realmente fatti sulle visualizzazioni di pagina quotidiane. In tal caso, decidere di dividerli in un'altra tabella è un'ottimizzazione delle prestazioni che dovrebbe essere eseguita solo se raggiunge i propri obiettivi di prestazione.

In generale, il partizionamento verticale è utile se si interrogano queste nuove colonne raramente e distintamente dalle altre colonne nella tabella originale. Inserendo quelle colonne in un'altra tabella che condivide lo stesso PK della tabella esistente, è possibile interrogarlo direttamente quando si desidera quelle nuove colonne e ottenere un throughput molto maggiore poiché si avranno molte più righe per pagina sul disco per questa nuova tabella poiché tutte le colonne della tabella originale non saranno posizionate su quelle righe. Tuttavia, se interrogherai sempre queste colonne insieme alle colonne nella tabella originale, allora una partizione verticale non avrebbe molto senso poiché dovrai sempre unire esterno per ottenerle. Le pagine dalle tabelle su disco entrano nel pool buffer di un DBMS in modo indipendente, mai pre-unito, e in tal modo l'unione dovrà avvenire ad ogni esecuzione della query anche se i dati sono bloccati nel pool di buffer. In questo scenario, renderle NULLABILI nella tabella originale consentirebbe al motore di archiviazione DBMS di memorizzarle in modo efficiente quando NULL ed eliminare la necessità di unirsi al recupero.

Mi sembra che il tuo caso d'uso sia il secondo e aggiungerli come NULLABLE alla tabella originale è la strada da percorrere. Ma come per qualsiasi altra cosa nella progettazione del database, dipende e per prendere la decisione giusta è necessario conoscere il carico di lavoro previsto e da cosa dipende la scelta. Un buon esempio di un caso d'uso corretto per il partizionamento verticale potrebbe essere un pannello di ricerca di una persona, in cui l'applicazione contiene alcune informazioni popolate molto raramente su una persona su cui qualcuno potrebbe voler cercare ma lo fa raramente. Se metti queste informazioni in una tabella diversa hai alcune buone opzioni per le prestazioni. Puoi scrivere la ricerca in modo da avere 2 query: una che utilizza solo le informazioni principali, sempre popolate per la ricerca (come il cognome o SSN), e uno che si unisce alle informazioni popolate molto raramente solo quando sono richieste per la ricerca. Oppure potresti sfruttare l'ottimizzatore DBMS se è abbastanza intelligente da riconoscere per un dato set di variabili host che il join esterno non è necessario e non lo eseguirà, e quindi devi solo creare 1 query.

Quale piattaforma DBMS stai usando? Il modo in cui la piattaforma gestisce l'archiviazione delle colonne NULL, ottimizza la query, così come la disponibilità del supporto delle colonne sparse (SQL Server ha questo) influenzerà la decisione. In definitiva, consiglierei di provare entrambi i progetti in un ambiente di test con dati di dimensioni di produzione e carico di lavoro e di vedere quale raggiunge meglio i tuoi obiettivi prestazionali.


Non mi è chiaro cosa intendi per "Tuttavia, se interrogherai sempre queste colonne insieme alle colonne nella tabella originale, una partizione verticale non avrebbe molto senso in quanto dovrai sempre unire all'esterno per ottenerle". , dovresti fare un join esterno solo quando desideri che le colonne primarie siano disponibili o meno, altrimenti utilizzeresti un INNER JOIN e, nella maggior parte dei casi, sarebbe utile (ridurre il numero di righe esaminate ).
jmoreno,

Grazie per tutto l'aiuto qui .. In effetti sono andato con l'aggiunta dei campi, ma dopo aver riflettuto su questo, ho visto che avrei dovuto avere un paio di altri tavoli per identificare meglio tutto. Quello che alla fine è arrivato è visitatore visitatore (che ha un visitatore_id e contiene la fonte) page_viste (che ha vistor_id e visitor_visit_id) poiché voglio sapere esattamente quale page_view è attribuito alla visita, ho aggiunto quel link. Ho lottato per un po ', ma penso che sia stata la decisione giusta
cgmckeever

10

Personalmente mi spiego verso l'aggiunta di colonne alla tabella esistente. Il nuovo tavolo non ti compra davvero nulla:

  • non si risparmia molto spazio perché i valori NULL nella tabella originale non occupano spazio e la nuova tabella necessita di un tipo di identificatore che compensi comunque eventuali risparmi
  • le tue domande diventano più complesse ... where newcolumn is not nulldiventa aleft outer join

Nella singola tabella significa solo che le dimensioni della riga possono variare da pagina a pagina, ma ciò non dovrebbe influire su molte delle pagine esistenti, soprattutto se l'indice cluster si trova su una colonna che aumenta monotonicamente (identità o data / ora).


Poiché la tabella non è attualmente ampia (in base alla descrizione) e questi dati non la renderanno troppo ampia, sarei d'accordo.
HLGEM,

4

Date le informazioni che hai fornito, e con l'obiettivo solo della normalizzazione generale, aggiungerei semplicemente colonne nullable, ma non hai fornito abbastanza informazioni su come verranno utilizzati i dati per sapere quale sia il modo migliore per modellarli è.

A seconda di come si utilizzano realmente questi dati, è possibile prendere in considerazione un modello di dati diverso. Se stai inserendo questi dati per i rapporti, potresti voler esaminare un modello dimensionale, che può essere più efficiente per alcuni tipi di rapporti, ad esempio l'analisi dell'ora del giorno funziona bene con una dimensione data e ora divisa.

Per rispondere a domande analitiche, come "qual è l'ora del giorno più popolare per le visite da campagne come X" o "in quale giorno di una campagna vediamo il maggior numero di visite all'ora", una singola colonna di data-time non funzionerà molto bene (ma questo può anche essere suddiviso in un modello relazionale) e ci sono molti casi in cui potresti trattare l'indirizzo IP come una dimensione (forse con qualche tipo di dati geografici in un fiocco di neve).

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.