Domanda

Ho il compito di archiviare una grande quantità di dati GPS e alcune informazioni extra nel database e di accedervi per la segnalazione e altre attività non frequenti.

Quando ricevo un messaggio dal dispositivo GPS può avere un numero variabile di campi. Ad esempio

Messaggio 1: DeviceId Lat Lon Speed ??Course DIO1 ADC1
Messaggio 2: DeviceId Lat Course DIO2 IsAlarmOn
Messaggio 3: DeviceId Lat Lon Height Course DIO2 IsAlarmOn ecc. Fino a 20-30 campi

Non esiste un modo per unificare il numero di campi: fornitori di dispositivi diversi, protocolli diversi, ecc. E un altro mal di testa è la dimensione del database e la necessità di supportare il maggior numero possibile di fornitori di database (viene utilizzato NHibernate).

Quindi mi è venuta l'idea di archiviare i messaggi in questo modo:
Tabella 1 - Tracce
PK - TrackId
TrackStartTime
TrackEndTime
FirstMessageIndex (memorizza MessageId)
LastMessageIndex (memorizza MessageId)
DeviceId (non un FK)

Tabella2 - Messaggi
PK - MessageId
TimeStamp
FirstDataIndex (memorizza DataId)
LastDataIndex (memorizza DataId)

Tabella 3 - MessageData
PK - DataId
doppio dato
breve DataType

Tutti gli indici sono assegnati con hilo. Ottimizzato le mie query in modo che Nhibernate sia in grado di gestire rapidamente la generazione di messaggi 3000 + k (veeeeeery). Sono contento della perfomance atm. Ma non so come funzionerà a 50 + GB o 100+ GB.

Sarà molto grato per eventuali suggerimenti e suggerimenti sul mio problema e sul design dello spazio di archiviazione =)
Grazie, Alexey
PS.Spiacente per il mio inglese =)

È stato utile?

Soluzione

In poche parole, la tua applicazione, in particolare la struttura eterogenea dei messaggi ricevuti dai dispositivi GPS, spinge il tuo progetto verso una struttura di archivio dati EAV (per cui l'Entità è il messaggio, l'attributo è il "quotate MessageData.DataType" e il valore è sistematicamente un doppio.)

Le tre tabelle progettate che descrivi nella domanda, tuttavia sembrano discostarsi un po 'da un'implementazione EAV tradizionale, nel senso che esiste una sequenza implicita nel modo in cui viene archiviato MessageData per cui tutti i i punti dati per un determinato messaggio sono numerati in sequenza (DataId) e il collegamento da un messaggio ai relativi punti dati sarà guidato da DataId all'interno di un intervallo.
    Questa è una cattiva idea ! Molti problemi con ciò, in particolare quello che introduce un collo di bottiglia non necessario per l'inserimento di messaggi, Impossibile iniziare a inserire un secondo messaggio fino a quando tutti i punti dati per il messaggio precedente. Un altro problema è che rende difficile l'indicizzazione della relazione tra messaggio e punto dati (il DBMS sottostante non sarà efficiente). == > Suggerimento: imposta MessageId come chiave esterna nella tabella MessageData . (e possibilmente rilasciare DataId PK nella tabella MessageData del tutto, solo per risparmiare spazio, a spese di dover usare una chiave composita per fare riferimento a un particolare record in questa tabella, ad esempio per scopi di manutenzione)

Un altro suggerimento è quello di memorizzare gli attributi più comuni (punti dati) a livello della tabella dei messaggi . Ad esempio, Lat e Long, ma forse anche Course o alcuni allarmi, ecc. Il motivo per cui queste informazioni sono giuste con il messaggio è di ottimizzare le query ai dati (limitando il numero di self join necessari con la tabella MessageData.

Poiché sia ??le tabelle Messaggi che MessageData potrebbero non contenere parte del messaggio, è possibile che si desideri rinominare quest'ultima tabella MessageDetail o un nome simile.

Infine, potrebbe essere una buona idea consentire valori di dati diversi da quelli del doppio tipo . Prevedo che alcuni degli avvisi siano semplicemente booleani, ecc. Oltre a consentire di accettare diversi tipi di punti dati (ad esempio stringhe di messaggi di errore brevi ...), ciò potrebbe anche darti l'opportunità di dividere i punti dati su più "dettagli". tabelle: una per i doppi, una per i booleani, una per le stringhe ecc. Questo modo di fare complica lo schema, nel senso che è quindi necessario creare alcuni di questi dettagli nel modo in cui vengono prodotte le query, ma può fornire un potenziale per guadagni in termini di prestazioni / ridimensionamento.

Altri suggerimenti

Cercherò di descrivere come funziona ora più dettagliatamente in risposta, perché i commenti hanno lunghezza fissa =) Ecco la sequenza di ricezione:
1. Il servizio riceve i messaggi da MSMQ (il numero di messaggi può differire e utilizza 500 pacchetti di massa di messaggi).
2. Quindi perfeziona gli ID dispositivo distinti.
3. Per ogni ID dispositivo utilizza cache di archiviazione isolata MS EntLib con struttura:
   DeviceId - > Elenca dove DeviceId è la chiave di ricerca.
4. Se abbiamo più di 1k messaggi nella cache, scrivili in db in una sequenza e dopo scrivi " indice " alla tabella di ricerca:
Indice: id
serial_id
index_start_datetime
index_end_datetime
index_first_dataid
index_last_dataid
5. Pulisce la cache per questo DeviceId

Inoltre, conservo i dati in coppia: id data1 tipo data2
ad esempio lat lon, speed course, adc1 adc2, dio1, dio2 e se non esiste un valore accoppiato: valore 0

Ho scelto double perché posso archiviare ogni tipo di dispositivo dati che vi invia. Non inviare stringhe, ma la maggior parte di esse sono in stile CSV come 1,0,23,50,0000N30,00000,1,2,12,0,1,2 ecc. Anche gli allarmi e così via hanno lo stesso tipo di dati. Quando ho bisogno di ottenere alcuni dati, trovo solo gli indici per una determinata finestra di datetime e DeviceId e ottengo i dati reali sapendo quando inizia e finisce. E non ci sono query complesse. Solo 2 semplici. Un altro codice lo sta interpretando usando alcuni protocolli "mapping". Grazie per il suggerimento EAV. Penso che vada bene. La prima tabella Track è per raggruppare i messaggi e per ottenerli rapidamente nell'algoritmo di retrival che ho descritto in precedenza stringhe di coppia.

Sto scrivendo un'applicazione simile. Suggerisco di riconoscere tutti i possibili valori dai fornitori e creare uno schema adeguato con tutti i campi necessari. Grazie a questo puoi scrivere query di reporting performanti / più semplici.

Inoltre puoi creare campi che contengono dati specificati (in lunghezza), il che significa che puoi salvare spazio e migliorare le prestazioni.

Ho un fornitore con valori noti, quindi ho creato una tabella per questo. Questa tabella può essere facilmente partizionata dal meccanismo nativo di MS SQL Server.

Quindi, la mia situazione più semplice mi permette di scrivere una procedura memorizzata per salvare i dati. Non esiste NHibernate, solo puro ICommand.

Il resto dell'applicazione utilizza NHibernate.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top