it-swarm.it

Timeseries: SQL o NoSQL?

Non mi interessano le differenze generali tra SQL e NoSQL (o le loro differenze tradizionali).

Attualmente sto cercando di modificare l'archiviazione delle nostre serie storiche interne. Tutti contengono dati finanziari provenienti da diverse fonti. Attualmente, stiamo memorizzando i nostri dati in un database proprietario. È molto NoSQL, che ha il suo linguaggio di query.

Sono interessato all'input della community: come memorizzeresti i dati in un database SQL? Quali sono i meriti per l'utilizzo di SQL su un NoSQL, in particolare per le serie storiche? Sono pazzo per aver considerato di archiviarlo in SQL?

Il nostro set di dati è costituito da milioni di serie temporali, con circa il 10% di queste contenenti milioni di record ciascuna. Le serie temporali sono organizzate gerarchicamente:/Mercato/Strumento/Valore/Frequenza, dove:

  • Il mercato è uno scambio di valori mobiliari, ecc., Fondamentalmente una raccolta di strumenti, di solito strumenti simili.
  • Lo strumento è uno strumento. Questo potrebbe essere un indicatore (Brent Crude), un'equità (GOOG), ecc
  • Il valore è uno dei molteplici tipi di dati per uno strumento. Questo potrebbe essere vicino, alto, basso, ecc
  • La frequenza è la frequenza di determinati valori di serie temporali. Settimanale, giornaliera, mensile, tick, arbitraria, ecc.

Come verrebbero archiviati i dati in un db SQL? Un grande tavolo (forse partizionato da qualcosa), un tavolo per mercato o strumento, un tavolo per serie storica.

Grazie in anticipo.

33
Nicolas

In generale, per un set di dati così strutturato ho il sospetto che tu possa scrivere un formato di dati personalizzato che è stato più veloce per la maggior parte delle operazioni quotidiane (vale a dire estrazioni di piccoli dati da un tempo arbitrario). Il vantaggio di passare a uno strumento DB standard è probabilmente in alcuni extra, ad esempio query ad hoc, accesso multiplo, replica, disponibilità ecc. È anche più semplice assumere un aiuto per mantenere un archivio di dati basato su standard.

Se mi chiedessero di impostare un database per archiviare quei dati, farei quanto segue:

Schema proposto

(1) I dati principali sono inseriti in numerose (1000) di singole tabelle, ciascuna contenente due colonne:

  1. time: un tipo di dati DATETIME SQL o un tipo numerico di qualche epoca (questa è la chiave primaria)
  2. valore: digitato come appropriato per i tuoi dati. Per impostazione predefinita, utilizzare il float a precisione singola, tuttavia un tipo di dati a virgola fissa potrebbe essere più appropriato per le transazioni finanziarie. Questo probabilmente non è indicizzato.

Queste tabelle diventeranno piuttosto grandi e potresti volerle partizionare manualmente per (ad esempio) anno. Ma dovrai controllare le prestazioni del sistema e ottimizzare come appropriato.

Queste tabelle hanno bisogno di nomi univoci e ci sono un paio di opzioni. Potrebbero essere leggibili dall'uomo (ad esempio nyse_goog_dailyhighs_2010) o (le mie preferenze) casuali. In entrambi i casi è necessario un set di tabelle di metadati e nomi di tabelle casuali impediscono agli sviluppatori di dedurre qualcosa nel nome che non si intendeva dedurre.

(2) I metadati sono memorizzati in tabelle separate, come richiesto dall'applicazione :

Per tenere traccia dei metadati è necessaria una tabella o un set di tabelle aggiuntivi. Queste tabelle conterranno dati su scambio, strumento, valore, frequenza, intervalli di date, provenienza (da dove provengono i dati), oltre a tutto ciò di cui hai bisogno. Questi sono associati ai nomi delle tabelle di dati.

Se ci sono abbastanza dati, questa ricerca potrebbe effettivamente fornire un nome di tabella e un nome di database, consentendo una sorta di sharding dei dati auto-implementato (se questo è l'uso corretto del termine). Ma lo terrei in riserva.

Quindi a livello di applicazione interrogherei le tabelle dei metadati per determinare dove si trovavano i miei dati e quindi eseguire query relativamente semplici sulle tabelle dei big data per ottenere i miei dati.

Vantaggi:

  • La mia esperienza (relativamente limitata) è che i database possono generalmente gestire un gran numero di piccole tabelle più facilmente di un numero minore di grandi tabelle. Questo approccio consente anche una manutenzione più semplice (ad es. Eliminazione di vecchi dati, ricostruzione di una tabella corrotta, creazione/ricarica da backup, aggiunta di una nuova entità). Ciò disaccoppia completamente i diversi tipi di dati, se (ad esempio) si dispone di dati a velocità diverse o che richiedono tipi di dati diversi.

  • Questo concetto di tabella scarna dovrebbe anche consentire un accesso rapido al disco per quello che sospetto sia la query più comune, un intervallo contiguo di dati da una singola entità. La maggior parte delle applicazioni di dati ha un I/O su disco limitato, quindi vale la pena considerare. Come ha già suggerito un commentatore, questa è la mia applicazione ideale per un database orientato alle colonne, ma devo ancora trovare un prodotto orientato alle colonne che sia abbastanza mainstream per poter scommettere sulla mia carriera. Questo schema si avvicina molto.

Svantaggi:

  • Circa metà dello spazio su disco è dedicata alla memorizzazione di timestamp, quando francamente 100 o 1000 delle tabelle avranno gli stessi dati esatti nella colonna timestamp. (In realtà questo è un requisito se si desidera eseguire semplici join di tabelle).

  • La memorizzazione dei nomi delle tabelle e l'esecuzione della ricerca dinamica richiedono molta complessità dell'applicazione e operazioni sulle stringhe, il che mi fa rabbrividire. Ma sembra ancora meglio delle alternative (discusso di seguito).

Considerazioni:

  • Fai attenzione agli arrotondamenti nel tuo campo temporale. Vuoi che i tuoi valori siano abbastanza rotondi da consentire i join (se appropriato), ma abbastanza precisi da non essere ambigui.

  • Fare attenzione ai fusi orari e all'ora legale. Questi sono difficili da testare. Vorrei applicare un requisito UTC sull'archivio dati (che potrebbe rendermi impopolare) e gestire le conversioni nell'applicazione.

Variazioni:

Alcune variazioni che ho considerato sono:

Piegatura dei dati: Se la serie temporale è equidistante, utilizzare una colonna timestamp e (ad esempio) 10 colonne dati. Il timestamp ora si riferisce al tempo della prima colonna di dati e le altre colonne di dati sono assunte equamente distanziate tra quel timestamp e quello successivo. Ciò consente di risparmiare molto spazio di archiviazione precedentemente utilizzato per archiviare i timestamp, a un costo di complessità delle query e/o delle applicazioni. Intervallo contiguo, le query a singola entità ora richiedono meno accesso al disco.

Multiplexing: Se è noto che più serie temporali utilizzano le stesse serie temporali, utilizzare un timestamp e (ad esempio) 10 colonne di dati come descritto sopra . Ma ora ogni colonna rappresenta una serie temporale diversa. Ciò richiede un aggiornamento della tabella dei metadati, che non è una ricerca nel nome della tabella e della colonna. Lo spazio di archiviazione è ridotto. Le query rimangono semplici. Tuttavia, per un intervallo contiguo, le query a singola entità ora richiedono un accesso al disco significativamente maggiore.

Mega-table: Porta il concetto di "multiplazione" all'estremo e metti tutti i dati in una singola tabella, una volta serie temporali per colonna. Ciò richiede grandi quantità di accesso al disco per intervalli contigui, query di singole entità ed è un incubo per la manutenzione. Ad esempio, l'aggiunta di una nuova entità ora richiede un comando MODIFY TABLE su una tabella many TB.

Per ulteriori discussioni su questo formato, vedere le varie risposte in: Troppe colonne in MySQL

Tabella completamente normalizzata: Invece di utilizzare molte tabelle a 2 colonne, è possibile utilizzare una tabella a tre colonne, in cui le colonne sono time, dataid e valore. Ora le tue tabelle di metadati devono solo cercare valori ID, anziché tablenames o nomi di colonne, il che consente di inserire più logica nelle query SQL, piuttosto che nel livello dell'applicazione.

Circa i 2/3 dello spazio di archiviazione vengono ora consumati con le colonne di normalizzazione, quindi questo utilizzerà molto spazio su disco.

È possibile utilizzare un ordine di chiave primario di (dataid, timestamp) per query contigue, singole entità veloci. In alternativa, è possibile utilizzare un ordine di chiave principale di (timestamp. Dataid) per inserimenti più rapidi.

Tuttavia, anche dopo aver considerato queste variazioni, il mio piano per il mio prossimo sviluppo è costituito da molte tabelle, ciascuna a due colonne. Quello o il metodo che presto verrà pubblicato da qualcuno più saggio di me :).

26
Pursuit

Usa MongoDB, puoi creare raccolte al volo molto rapidamente. Cerca di organizzare i tuoi dati in database separati e raccolte all'interno di tali database. Considera la quantità di memoria necessaria per cercare di mantenere ogni frammento nella memoria di sistema, se hai bisogno di un recupero rapido. Stupido attenersi a una soluzione interna, se c'è qualcosa di più fresco là fuori che si evolverà lungo le linee di cui hai bisogno. Sembra una buona iniziativa.

1
Dantalion