È una cattiva pratica archiviare file di grandi dimensioni (10 MB) in un database?


188

Attualmente sto creando un'applicazione Web che consente agli utenti di archiviare e condividere file di dimensioni 1 MB - 10 MB.

Mi sembra che l'archiviazione dei file in un database rallenti in modo significativo l'accesso al database.

È una preoccupazione valida? È meglio archiviare i file nel file system e salvare il nome e il percorso del file nel database? Esistono best practice relative alla memorizzazione di file quando si lavora con un database?

Sto lavorando in PHP e MySQL per questo progetto, ma il problema è lo stesso per la maggior parte degli ambienti ( Ruby on Rails , PHP , .NET ) e database (MySQL, PostgreSQL ).


9
Domanda correlata su DBA.SE: File - nel database o no?
Nick Chammas,

11
Sorpreso dal fatto che nessuno abbia pubblicato le ricerche sulla SM fatte su questo problema (per SQL Server 2008): BLOB o Not BLOB: archiviazione di oggetti di grandi dimensioni in un database o in un filesystem
Oded,

2
grande è una quantità relativa, io (e molti altri probabilmente) non la vedo 10MBcosì grande in un sistema moderno.

27
Questo è un argomento in base alle FAQ - si inserisce sotto i "modelli di progettazione" di proiettili (antenne di barra) e "architettura software". Perché è stato chiuso?
Izkata,

21
Non vedo alcuna vaghezza nella domanda come è adesso. Non ho idea del perché fosse chiuso.
reinierpost,

Risposte:


139

Motivi a favore della memorizzazione dei file nel database:

  1. Coerenza ACID incluso il rollback di un aggiornamento che risulta complicato quando i file vengono archiviati all'esterno del database. Questo non deve essere lucidato leggermente. Avere i file e il database sincronizzati e in grado di partecipare alle transazioni può essere molto utile.
  2. I file vanno con il database e non possono essere orfani da esso.
  3. I backup includono automaticamente i file binari.

Motivo per non archiviare i file nel database:

  1. La dimensione di un file binario differisce tra i database. Su SQL Server, quando non si utilizza l'oggetto FILESTREAM, ad esempio, è di 2 GB. Se gli utenti devono archiviare file di dimensioni maggiori (come ad esempio un film), devi saltare attraverso i cerchi per far sì che la magia accada.
  2. Aumenta la dimensione del database. Un concetto generale che dovresti prendere a cuore: il livello di conoscenza richiesto per mantenere un database aumenta in proporzione alla dimensione del database.Vale a dire, i database di grandi dimensioni sono più complicati da gestire rispetto ai database di piccole dimensioni. La memorizzazione dei file nel database può rendere il database molto più grande. Anche se dire che un backup completo giornaliero sarebbe stato sufficiente, con una dimensione del database più grande, potresti non essere più in grado di farlo. Potrebbe essere necessario considerare di inserire i file in un gruppo di file diverso (se il database lo supporta), modificare i backup per separare il backup dei dati dal backup dei file, ecc. Nessuna di queste cose è impossibile da imparare, ma fare aggiungere complessità alla manutenzione, il che significa costo per l'azienda. Database più grandi consumano anche più memoria mentre cercano di immagazzinare quanti più dati possibile nella memoria.
  3. La portabilità può essere un problema se si utilizzano funzionalità specifiche del sistema come l' FILESTREAMoggetto di SQL Server e è necessario migrare a un diverso sistema di database.
  4. Il codice che scrive i file nel database può essere un problema. Una società per la quale ho consultato non tante lune fa ad un certo punto ha collegato un frontend di Microsoft Access al loro server di database e ha usato la capacità di Access di caricare "qualsiasi cosa" usando il suo controllo Ole Object. Successivamente cambiarono per usare un controllo diverso che faceva ancora affidamento su Ole. Molto più tardi qualcuno ha cambiato l'interfaccia per memorizzare il file binario non elaborato. Estrarre quegli oggetti Ole era un nuovo livello di inferno. Quando si memorizzano i file nel file system, non è necessario un livello aggiuntivo per avvolgere / modificare / modificare il file di origine.
  5. È più complicato pubblicare i file su un sito Web. Per farlo con colonne binarie, devi scrivere un gestore per eseguire lo streaming del file binario dal database. È anche possibile fare questo anche se si memorizzare percorsi di file, ma non si hanno a che fare questo. Ancora una volta, l'aggiunta di un gestore non è impossibile ma aggiunge complessità ed è un altro punto di errore.
  6. Non puoi sfruttare l'archiviazione cloud. Supponiamo che un giorno desideri archiviare i tuoi file in un bucket Amazon S3. Se ciò che memorizzi nel database sono percorsi di file, ti viene offerta la possibilità di cambiarli in percorsi su S3. Per quanto ne so, ciò non è possibile in nessuno scenario con nessun DBMS.

IMO, ritenendo l'archiviazione dei file nel database o meno "cattiva" richiede ulteriori informazioni sulle circostanze e sui requisiti. Le dimensioni e / o il numero di file saranno sempre piccoli? Non ci sono piani per utilizzare il cloud storage? I file verranno pubblicati su un sito Web o un eseguibile binario come un'applicazione Windows?

In generale, la mia esperienza ha scoperto che la memorizzazione dei percorsi è meno costosa per l'azienda, anche tenendo conto della mancanza di ACID e della possibilità di orfani. Tuttavia, ciò non significa che Internet non sia una legione con storie di mancanza di controllo ACID che non vanno bene con l'archiviazione dei file, ma significa che in generale quella soluzione è più facile da costruire, comprendere e mantenere.


Perché non puoi usare i CDN? Questo è uno scenario supportato con praticamente ogni CDN di cui abbia mai sentito parlare.
Billy ONeal,

@BillyONeal: non è possibile utilizzare un CDN e archiviare il file nel database. A meno che tu non stia bene con la duplicazione, non puoi avere entrambi.
Thomas,

3
Ehm, il punto centrale di una CDN è la duplicazione. Le CDN si limitano a memorizzare nella cache la destinazione di un indirizzo Web: l'unico requisito è che sia presente un host HTTP che serve il contenuto e che il contenuto cambi raramente. (Come diavolo dovrebbe dire la CDN da dove hai estratto l'immagine comunque?)
Billy ONeal

3
@BillyONeal - Tuttavia, penso che questa sia una cattiva scelta di parole da parte mia e ho adattato la mia risposta. In particolare, se si desidera utilizzare l'archiviazione cloud (e quindi forse utilizzare una CDN con l'archiviazione cloud), non è possibile farlo in modo nativo con la soluzione di archiviazione del database. Dovresti scrivere una routine di sincronizzazione per estrarre i file dal database e quindi inviarli al tuo provider di archiviazione cloud.
Thomas,

@BillyONeal - In un certo senso, il tuo commento è stato la risposta migliore. Puoi avere tutti i vantaggi dell'archiviazione DB, ma nessuno dei problemi.
B Sette,

89

In molti casi, questa è una cattiva idea. Si gonfia i file del database e causa diversi problemi di prestazioni. Se si attaccano i BLOB in una tabella con un gran numero di colonne è anche peggio.

Però! Alcuni database, come SQL Server, hanno un tipo di colonna FILESTREAM. In questo caso, i dati vengono effettivamente archiviati in un file separato sul server di database e nella tabella viene salvato solo un ID nel file. In questo caso non vedo molte ragioni per non conservare i dati nel server SQL. I file vengono automaticamente inclusi come parte del backup del server e il database e i file non vengono mai sincronizzati. Il problema con il suggerimento di Tony di archiviare i nomi dei file è che il database e il filesystem possono non essere sincronizzati. Il database affermerà che esiste un file quando è stato eliminato sul disco. Se un processo modifica il database e quindi si arresta in modo anomalo, i file e il database non corrisponderanno (ovvero nessun ACID con file esterni a un database).


21
Non sono d'accordo con l'affermazione `Se un processo sta modificando il DB e quindi si arresta in modo anomalo, i file e il DB non corrisponderanno. Se si avvolge l'intero processo in una transazione (crea file, convalida file, aggiorna db) e genera messaggi di errore quando qualcosa va storto è abbastanza facile mantenerli sincronizzati.
Briddums,

3
Sono d'accordo con questo: considera lo scenario: archivia il file nel filesystem (senza cancellare quello vecchio), aggiorna il DB, in caso di successo cancella il vecchio file, al rollback elimina il nuovo file. Scenario peggiore: se il processo viene interrotto, hai un file orfano. Ma hai sempre i file a cui fa riferimento DB nella versione corretta.
vartec,

2
Altri potenziali problemi con il metodo File / DB: 1) è necessario eseguire gli aggiornamenti come copia su scrittura. Se il processo si arresta in modo anomalo durante un aggiornamento, lo stato del DB verrà ripristinato, il file no. 2) Per fare ciò è necessaria una sorta di garbage collection del vecchio file. 3) Memorizzare tutto nel DB significa che le versioni del DB e dei file sono sincronizzate dopo i backup. Ripristina il tuo DB al suo stato 2 settimane fa ... ora che cosa dove il contenuto dei file in quel momento?
Timothy Baldridge,

3
@briddums - No, poiché SQL Server si integra direttamente nel file system e gestisce tali file per conto del sistema operativo. Non li ho usati io stesso, ma la documentazione fa sembrare FILESTREAM e le sue FileTable discendenti ti garantiscono il meglio dei due mondi: i file sono strettamente legati al database e ai dati relativi (che ti consentono di gestire centralmente i tuoi dati) senza gonfiare il Banca dati.
Nick Chammas,

1
Sono d'accordo con Nick. Abbiamo sostituito il nostro sistema Disk + DB con colonne FILESTREAM e non abbiamo mai guardato indietro. È davvero bello poter collegare i file ad altri tavoli tramite FK. Quindi puoi effettivamente dire "ogni persona deve avere uno o più documenti HR associati a loro", o qualcos'altro del genere.
Timothy Baldridge,

35

Sì, è una cattiva pratica.

Impatto sulle prestazioni sul DB:

  • se lo fai SELECTcon una qualsiasi colonna BLOB, farai sempre un accesso al disco, mentre senza BLOB avrai la possibilità di ottenere i dati direttamente dalla RAM (il DB con throughput elevato sarà ottimizzato per adattarsi alle tabelle nella RAM);
  • la replica sarà lenta, il ritardo di replica alto, poiché dovrà spingere BLOB sugli slave. L'elevato ritardo di replica causerà tutti i tipi di condizioni di gara e altri problemi di sincronizzazione, a meno che non lo si consideri esplicitamente;
  • I backup / ripristini DB richiederanno molto più tempo;

Vantaggio di velocità - nessuno ! Mentre alcuni filesystem più vecchi non gestiscono bene le directory con milioni di file, la maggior parte dei moderni non ha alcun problema e in effetti usa lo stesso tipo di strutture dati dei BD (in genere B-tree). Ad esempio ext4 (filesystem Linux predefinito) usa Htree .

Conclusione: ostacolerà le prestazioni del DB e non migliorerà le prestazioni di recupero dei file.

Inoltre, dal momento che stai parlando di un'applicazione web - servire file statici direttamente dal filesystem usando un moderno webserver, che può fare sendfile()syscall è un enorme miglioramento delle prestazioni. Questo ovviamente non è possibile se stai recuperando file dal DB. Considera ad esempio questo benchmark , che mostra Ngnix che esegue 25K req / s con 1000 connessioni simultanee su un laptop di fascia bassa. Quel tipo di carico friggerebbe qualsiasi tipo di DB.


6
+1. Lascia che il tuo server web faccia quello che fa meglio, servendo i file dal disco. Non farlo chiedere a PHP, poiché PHP dovrà chiedere a MySQL, ecc.
Deizel,

3
Quando i programmatori impareranno che le prestazioni non sono tutto ciò che conta?
reinierpost,

2
@reinierpost: lol. probabilmente quando avremo maggiori arti liberali ;-)
vartec,

1
@BillyONeal: perché pensi che devi avere lo stesso server per contenuti statici e dinamici? Per quanto riguarda la sincronizzazione dei file tra server, esistono strumenti appositamente progettati per questo, molto più efficienti dei database. Usare il database come fileserver è come provare a martellare un chiodo con un cacciavite.
vartec,

1
@BillyONeal: Sono d'accordo che ci sono alcune "soluzioni" in cui ciò potrebbe funzionare, ho visto un sacco di configurazioni PHP amatoriali con immagini in MySQL. Tuttavia, in una tale configurazione un DB non supporterà mai un traffico elevato che serve BLOB.
vartec,

18

Ne sarei pragmatico e seguirò il principio "non ottimizzare ancora". Trova la soluzione che ha senso al momento e quella che hai le risorse di sviluppo per implementare correttamente. Ci sono molti potenziali problemi . Ma quelli non diventano necessariamente problemi reali. Ad esempio, probabilmente non sarebbe un problema se hai 100 utenti. Si potrebbe essere un problema se si dispone di circa 100.000 10.000.000 utenti. Ma in quest'ultimo caso, ci dovrebbe essere una base per maggiori risorse di sviluppo per affrontare tutte le questioni.

Ma l'archiviazione dei dati nel database ti solleva dalla gestione di altri problemi, ad esempio dove devono essere archiviati i file, come devono essere sottoposti a backup, ecc. Dato che stai scrivendo un'applicazione web, sarebbe un'ottima idea per motivi di sicurezza per assicurarsi che il processo che ospita l'applicazione non abbia accesso in scrittura al file system, quindi è necessario configurare il server in modo che il processo abbia accesso in lettura / scrittura alla cartella in cui sono archiviati i dati.

Personalmente sceglierei di archiviare i dati nel database, ma assicurerei che i BLOBS non vengano letti fino a quando non sono realmente necessari, cioè nessun "SELECT * FROM ..." eseguito su quelle tabelle contenenti blog. E farei in modo che il design semplifichi lo spostamento dei dati dal database, nel filesystem, se riscontri problemi di prestazioni. Ad esempio, archiviare le informazioni sul file in una tabella File separata , mantenendo così le informazioni sul file lontano da altre entità aziendali.

Supponendo che si disponga di una classe File per rappresentare un file letto nel database, l'impatto della codifica di spostarlo successivamente sarà minimo.


Questo è un suggerimento eccellente. Non iniziare a risolvere problemi che non hai.
Pesante

16

Microsoft ha pubblicato un libro bianco su questo alcuni anni fa. Si concentra su SqlServer, ma potresti trovare alcune informazioni interessanti qui:

BLOB o non BLOB? Archiviazione di oggetti di grandi dimensioni in un database o un filesystem?

Una versione molto concisa della loro conclusione è:

Quando si confrontano il file system NTFS e SQL Server 2005, BLOBS di dimensioni inferiori a 256 KB vengono gestiti in modo più efficiente da SQL Server, mentre NTFS è più efficiente per BLOBS di dimensioni superiori a 1 MB.

Ti consiglierei di scrivere alcuni piccoli test per il tuo caso d'uso particolare. Tieni presente che devi fare attenzione agli effetti della cache. (Sono stato sorpreso la prima volta che ho ottenuto velocità di salvataggio su disco che sembravano avere un throughput più elevato di quanto fosse fisicamente possibile!)


4
Dovresti sapere che NTFS inizia a comportarsi in modo molto irregolare quando metti più di ~ 100K file in una singola directory. L'accesso ai file rallenta un po '(almeno un ordine di grandezza) e le operazioni di apertura dei file iniziano a fallire (apparentemente) in modo casuale. Ho riscontrato questo effetto su sistemi Windows 2008 e Windows 7. Quando ho ridistribuito i file tra più directory, tutto è tornato alla normalità. Da allora non so se la situazione sia migliorata.
Ferruccio,

11

La vecchia saggezza convenzionale di archiviare file al di fuori del database potrebbe non essere più valida. In linea di principio, preferirei l'integrità rispetto alla velocità e, con un moderno DBMS, puoi avere entrambi.

Tom Kyte sembra essere d'accordo :

Non conosco alcun vantaggio nell'archiviazione dei dati che voglio conservare per molto tempo al di fuori di un database.

Se è nel database, posso

assicurati che sia gestito professionalmente

eseguito il backup

recuperabile (con il resto dei dati)

assicurato

scalabile (prova a mettere 100.000 documenti in una singola directory, ora mettili nella tabella - quale "ridimensiona" - non è la directory)

Posso ripristinare (flashback) facilmente

Ho il blocco

Ho letto la coerenza ...


8

Sì.

Se servite un file dal vostro filesystem, il vostro server Web può usare il codice del kernel come sendfile () su BSD o Linux per copiare il file direttamente nel socket. È molto veloce e molto efficiente.

Servire i file fuori dal database significa che devi copiare i dati dal disco del server di database alla memoria del server di database, quindi dalla memoria del server db alla porta di rete del server db, quindi dalla rete al processo del tuo server Web, quindi di nuovo alla connessione di rete in uscita.

A meno che tu non abbia una buona ragione per non farlo, è sempre meglio servire file statici dal file system.


Questo è vero, ma non riesco a vedere dove l'utente afferma nella domanda che servirà i file statici dal database. Questo potrebbe benissimo essere file dinamici o file caricati dall'utente che, se archiviati nel filesystem separatamente dal database, ora devono essere sincronizzati e avere un processo di backup / ripristino separato.
maple_shaft

1
La mia comprensione è che la domanda riguarda la pubblicazione di file caricati dall'utente. "Attualmente sto creando un'applicazione Web che consente agli utenti di archiviare e condividere file [...] Mi sembra che memorizzare i file in un database [...]". Non penso sia davvero conveniente eseguire dump DB con un sacco di BLOB multi-megabyte nel database. Inoltre: sì, è difficile gestire i file; sincronizzazione, archiviazione, sono tutti più difficili. Tuttavia, non è molto più difficile e sacrificare le prestazioni online per salvare alcune righe nel tuo script di backup notturno è un grosso errore.
Evan P.

5

Il famoso Tom Kyte ha scritto che (Oracle) stanno utilizzando il database Oracle come file server e funziona perfettamente, anche più velocemente del normale file system, con piena transazione, nessuna perdita di prestazioni e con un singolo backup.

Sì, ma nota, sono i produttori di Oracle DB e per qualsiasi altro utente ci sono problemi di costo. L'uso di DB commerciali come Oracle per l'archiviazione dei file è semplicemente inefficace in termini di costi.

Tuttavia, con PostgreSQL ad esempio, è possibile semplicemente eseguire un'altra istanza DB solo per l'archiviazione BLOB. Hai quindi il pieno supporto transazionale. Ma la transazionalità costa spazio DB. È necessario che il database memorizzi più istanze BLOB per più transazioni simultanee. Su PostgreSQL è il più doloroso, poiché questo database memorizza i duplicati dei BLOB creati per la transazione vengono archiviati anche se non sono più necessari, fino al completamento del processo VACUUM.

Con l'archiviazione del filesystem, invece, devi essere molto attento quando qualcuno modifica il file, perché la transazione può essere ripristinata e la copia del file deve essere conservata fino a quando la vecchia versione non è più visibile.

Nel sistema in cui i file vengono solo aggiunti ed eliminati e l'accesso transazionale ai file non è un problema, l'archiviazione del file system sarà IMHO la scelta migliore.


Ciao, quando hai detto "l'utilizzo di ... Oracle per l'archiviazione di file è semplicemente inefficace in termini di costi", cosa succede se stiamo già utilizzando Oracle per l'archiviazione di altri dati non di file? Sarà ancora inefficace in termini di costi?
Xiao Peng - ZenUML.com

RE: "devi stare molto attento quando qualcuno modifica il file" ... come ex Oracle DBA, devo suggerire che i file di grandi dimensioni siano tenuti fuori dal database e che non permetti mai di modificarli. Le persone fanno errori. L'unico modo pratico per gestire il rollback (annulla) di quei file è implementare un sistema Copy On Write per loro. Tutte le versioni sono quindi mantenute e archiviate. Il più vecchio può essere spostato nella memoria remota, post elaborato per consolidare piccole modifiche in un archivio, ecc.
DocSalvager,

5

Di solito è meglio archiviare BLOB di grandi dimensioni in una tabella separata e mantenere solo un riferimento di chiave esterna al BLOB nella tabella principale. In questo modo, è ancora possibile recuperare il file dal database (quindi non è necessario alcun codice speciale) ed evitare i problemi relativi alle dipendenze di DB esterni (mantenendo sincronizzati DB e filesystem, ecc.), Ma si incorre in tale sovraccarico se ti unisci esplicitamente a quella tabella (o fai una chiamata separata). 10 MB non sono terribilmente grandi, i database commerciali più moderni non avranno problemi. L'unico motivo per cui memorizzerei un file nel filesystem è ridurre la larghezza di banda del database. Se il database sta mescolando molti di questi file, potrebbe essere necessario dividere il carico di lavoro e archiviare solo un descrittore di file di qualche tipo. Quindi puoi avere una chiamata separata per caricare il file da un altro server,


4

Potresti riscontrare alcuni di questi problemi:

  • Fare una SELECT *cosa che coinvolge la riga con il BLOB di grandi dimensioni richiede molto tempo, anche se non è necessario il BLOB (ovviamente dovresti fare una selezione specifica, ma a volte le applicazioni sono scritte in questo modo)
  • Fare un backup può richiedere molto più tempo. A seconda delle esigenze, potrebbe essere necessario bloccare le tabelle per l'ora del backup, quindi è possibile che si desideri ridurre i tempi di backup
  • Il ripristino richiederà anche molto più tempo.
  • Se esaurisci lo spazio, devi pensare a un modo (magari spostare l'intero database su un nuovo server) per risolvere questo problema. Memorizzando i file sul file system è sempre possibile montare un altro disco rigido e impostare collegamenti software.
  • La semplice ricerca in un file per il debug o altre informazioni non è così semplice. Ciò include anche script che potrebbero non avere accesso al database ma che necessitano di alcune informazioni da vari file.

Ovviamente ottieni anche alcuni vantaggi:

  • Il backup dei dati e dei menu dei file sono sincronizzati
  • La rimozione del file senza la conoscenza del database non è possibile
  • Non è necessario leggere il file dal disco ma è possibile farlo in un'istruzione sql
  • Puoi scaricare il database, includere il dump nel tuo ambiente di sviluppo e avere tutte le dipendenze proprio lì

Personalmente non lo faccio perché trovo i contro molto più pesanti dei professionisti. Ma come detto sopra dipende totalmente dal tuo caso d'uso e simili.


1

Alcuni sistemi di gestione dei contenuti di Enterpirse, come SiteCore, utilizzano un database per archiviare i dati delle pagine e un altro database per archiviare i file. Stanno usando MS SQL Server.


come risponde alla domanda posta?
moscerino del

Se fai un po 'di ricerca, scoprirai che SiteCore è uno dei sistemi di gestione dei contenuti aziendali più popolari. SiteCore supporta un gran numero di utenti simultanei e si adatta abbastanza bene, quindi sì, archiviare i file all'interno di un database separato non è una cattiva pratica se lo fai nel modo giusto.
šljaker,

1

Per un'implementazione pratica, ecco cosa potresti interessare:

Vantaggi:

  1. Tutti i contenuti dei file sono decisamente sincronizzati con la tua tabella. Come già detto nei commenti, il backup dei dati è assolutamente conveniente in quanto non è necessario mantenere i dati sincronizzati con il file system.
  2. Dalla codifica, è possibile ottenere il contenuto del file direttamente da una selezione SQL.
  3. Da una query, puoi persino filtrare il contenuto del file o le sue dimensioni in modo esplicito dall'istruzione SQL.

Svantaggi:

  1. Rispetto a un database di cui la struttura è semanticamente la stessa ma non memorizza il contenuto del file, il database tende a consumare radicalmente più memoria quando si esegue una query.
  2. Il backup automatico può causare problemi di prestazioni ma non molto. Immaginiamo che il tuo server database esegua il backup delle cose ogni 6 ore e che i database che hai stiano archiviando file da 10 MB per record. Quello scenario non è quello che vuoi.
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.