¿Es una mala práctica almacenar archivos grandes (10 MB) en una base de datos?

188

Actualmente estoy creando una aplicación web que permite a los usuarios almacenar y compartir archivos, de 1 MB a 10 MB de tamaño.

Me parece que almacenar los archivos en una base de datos ralentizará significativamente el acceso a la base de datos.

¿Es esta una preocupación valida? ¿Es mejor almacenar los archivos en el sistema de archivos y guardar el nombre y la ruta del archivo en la base de datos? ¿Existen mejores prácticas relacionadas con el almacenamiento de archivos cuando se trabaja con una base de datos?

Estoy trabajando en PHP y MySQL para este proyecto, pero es el mismo problema para la mayoría de los entornos ( Ruby on Rails , PHP , .NET ) y bases de datos (MySQL, PostgreSQL ).

B Seven
fuente
99
Pregunta relacionada sobre DBA.SE: Archivos: ¿en la base de datos o no?
Nick Chammas
11
Sorprendido de que nadie haya publicado la investigación de MS realizada sobre este tema (para SQL Server 2008): BLOB o no BLOB: Almacenamiento de objetos grandes en una base de datos o un sistema de archivos
Finalizado
2
grande es una cantidad relativa, yo (y muchos otros probablemente) no veo 10MBtan grande en un sistema moderno.
27
Esto es sobre el tema de acuerdo con las preguntas frecuentes: se ajusta a las viñetas "patrones de diseño" (barra diagonal) y "arquitectura de software". ¿Por qué estaba cerrado?
Izkata
21
No veo ninguna imprecisión en la pregunta como es ahora. No tengo idea de por qué estaba cerrado.
reinierpost

Respuestas:

139

Razones a favor de almacenar archivos en la base de datos:

  1. Consistencia de ACID, incluida la reversión de una actualización que es complicada cuando los archivos se almacenan fuera de la base de datos. Esto no debe pasarse por alto a la ligera. Tener los archivos y la base de datos sincronizados y poder participar en las transacciones puede ser muy útil.
  2. Los archivos van con la base de datos y no pueden quedar huérfanos a partir de ella.
  3. Las copias de seguridad incluyen automáticamente los archivos binarios.

Motivo contra el almacenamiento de archivos en la base de datos:

  1. El tamaño de un archivo binario difiere entre las bases de datos. En SQL Server, cuando no se usa el objeto FILESTREAM, por ejemplo, es de 2 GB. Si los usuarios necesitan almacenar archivos más grandes (como, por ejemplo, una película), tienes que saltar a través de los aros para que esa magia suceda.
  2. Aumenta el tamaño de la base de datos. Un concepto general que debe tener en cuenta: el nivel de conocimiento requerido para mantener una base de datos aumenta en proporción al tamaño de la base de datos.Es decir, las bases de datos grandes son más complicadas de mantener que las bases de datos pequeñas. Almacenar los archivos en la base de datos puede hacer que la base de datos sea mucho más grande. Incluso si dijera que una copia de seguridad completa diaria hubiera sido suficiente, con un tamaño de base de datos más grande, es posible que ya no pueda hacerlo. Puede que tenga que considerar colocar los archivos en un grupo de archivos diferente (si la base de datos lo admite), ajustar las copias de seguridad para separar la copia de seguridad de los datos de la copia de seguridad de los archivos, etc. Ninguna de estas cosas es imposible de aprender, pero sí Agregar complejidad al mantenimiento, lo que significa un costo para el negocio Las bases de datos más grandes también consumen más memoria, ya que intentan almacenar tantos datos en la memoria como sea posible.
  3. La portabilidad puede ser una preocupación si usa características específicas del sistema como el FILESTREAMobjeto de SQL Server y necesita migrar a un sistema de base de datos diferente.
  4. El código que escribe los archivos en la base de datos puede ser un problema. Una compañía a la que consulté hace no muchas lunas en algún momento conectó una interfaz de Microsoft Access a su servidor de base de datos y usó la capacidad de Access para cargar "cualquier cosa" usando su control Ole Object. Más tarde cambiaron para usar un control diferente que todavía dependía de Ole. Mucho más tarde, alguien cambió la interfaz para almacenar el binario sin formato. Extraer esos objetos viejos era un nuevo nivel del infierno. Cuando almacena archivos en el sistema de archivos, no hay una capa adicional involucrada para ajustar / modificar / alterar el archivo fuente.
  5. Es más complicado entregar los archivos a un sitio web. Para hacerlo con columnas binarias, debe escribir un controlador para transmitir el archivo binario desde la base de datos. También puede hacer esto incluso si almacena las rutas de los archivos, pero no tiene que hacerlo. Nuevamente, agregar un controlador no es imposible, pero agrega complejidad y es otro punto de falla.
  6. No puede aprovechar el almacenamiento en la nube. Supongamos que un día desea almacenar sus archivos en un bucket de Amazon S3. Si lo que almacena en la base de datos son rutas de archivos, puede cambiarlas por rutas en S3. Que yo sepa, eso no es posible en ningún escenario con ningún DBMS.

En mi opinión, considerar el almacenamiento de archivos en la base de datos o no como "malo" requiere más información sobre las circunstancias y los requisitos. ¿El tamaño y / o el número de archivos siempre serán pequeños? ¿No hay planes para usar el almacenamiento en la nube? ¿Se entregarán los archivos en un sitio web o en un ejecutable binario como una aplicación de Windows?

En general, mi experiencia ha encontrado que almacenar rutas es menos costoso para la empresa, incluso teniendo en cuenta la falta de ACID y la posibilidad de huérfanos. Sin embargo, eso no significa que Internet no sea una legión con historias de falta de control de ACID que va mal con el almacenamiento de archivos, pero sí significa que, en general, esa solución es más fácil de construir, comprender y mantener.

Thomas
fuente
¿Por qué no puedes usar CDN? Este es un escenario compatible con casi todos los CDN que he oído hablar.
Billy ONeal
@BillyONeal: no puede usar un CDN y almacenar el archivo en la base de datos. A menos que esté de acuerdo con la duplicación, no puede tener ambas.
Thomas
3
Erm, el objetivo de un CDN es la duplicación. Las CDN simplemente almacenan en caché el destino de una dirección web; el único requisito es que haya un host HTTP que sirva el contenido y que el contenido cambie raramente. (¿Cómo demonios se supone que la CDN debe decir de dónde
sacaste
3
@BillyONeal - Sin embargo, creo que esta es una mala elección de palabras de mi parte y he ajustado mi respuesta. Específicamente, si desea usar el almacenamiento en la nube (y luego quizás usar un CDN con su almacenamiento en la nube), no puede hacerlo de forma nativa con la solución de almacenamiento de la base de datos. Tendría que escribir una rutina de sincronización para extraer los archivos de la base de datos y luego enviarlos a su proveedor de almacenamiento en la nube.
Thomas
@BillyONeal: en cierto modo, tu comentario fue la mejor respuesta. Puede tener todos los beneficios del almacenamiento DB, pero ninguno de los problemas.
B Seven
89

En muchos casos, esta es una mala idea. Hinchará los archivos de la base de datos y causará varios problemas de rendimiento. Si pega los blobs en una tabla con una gran cantidad de columnas, es aún peor.

¡Sin embargo! Algunas bases de datos, como SQL Server, tienen un tipo de columna FILESTREAM. En este caso, sus datos se almacenan en un archivo separado en el servidor de la base de datos y solo se guarda en la tabla una ID del archivo. En este caso, no veo muchas razones para no mantener los datos en el servidor SQL. Los archivos se incluyen automáticamente como parte de la copia de seguridad del servidor, y la base de datos y los archivos nunca están fuera de sincronización. El problema con la sugerencia de Tony de almacenar nombres de archivos es que la base de datos y el sistema de archivos pueden desincronizarse. La base de datos afirmará que existe un archivo cuando se haya eliminado en el disco. Si un proceso está modificando la base de datos y luego falla, los archivos y la base de datos no coincidirán (es decir, no ACID con archivos fuera de una base de datos).

Timothy Baldridge
fuente
21
No estoy de acuerdo con la afirmación `Si un proceso está modificando la base de datos y luego se bloquea, los archivos y la base de datos no coincidirán '. Si envuelve todo el proceso en una transacción (crear archivo, validar archivo, actualizar db) y arrojar mensajes de error Cuando algo sale mal, es bastante fácil mantenerlos sincronizados.
briddums
3
Estoy con briddums en eso: considere el escenario: almacene el archivo en el sistema de archivos (sin eliminar el anterior), actualice DB, en caso de éxito elimine el archivo antiguo, en la reversión, elimine el archivo nuevo. El peor de los casos: si el proceso se interrumpe, tiene un archivo huérfano. Pero siempre tiene los archivos referenciados por DB en la versión correcta.
vartec
2
Otros posibles problemas con el método de archivo / base de datos: 1) debe realizar actualizaciones como copia en escritura. Si su proceso falla durante una actualización, el estado de la base de datos se revertirá y el archivo no. 2) Hacer esto requiere algún tipo de recolección de basura del archivo anterior. 3) Almacenar todo en la base de datos significa que las versiones de la base de datos y los archivos están sincronizados después de las copias de seguridad. Restaure su base de datos a su estado hace 2 semanas ... ahora, ¿dónde estaba el contenido de los archivos en ese momento?
Timothy Baldridge
3
@briddums: no, ya que SQL Server se integra directamente en el sistema de archivos y administra esos archivos en nombre del sistema operativo. No los he usado yo mismo, pero la documentación hace que se vea como FILESTREAM y sus FileTables descendientes le otorgan lo mejor de ambos mundos: los archivos están estrechamente vinculados a la base de datos y los datos relacionados (lo que le permite administrar sus datos de manera centralizada) sin hinchar el base de datos.
Nick Chammas
1
Estoy de acuerdo con Nick Hemos reemplazado nuestro sistema Disk + DB con columnas FILESTREAM y nunca miramos hacia atrás. Es realmente agradable poder tener archivos vinculados a otras tablas a través de FK. Por lo tanto, puede decir "cada persona debe tener uno o más documentos de recursos humanos asociados con ellos", o algo así.
Timothy Baldridge,
35

Sí, es una mala práctica.

Impacto en el rendimiento de la base de datos:

  • si hace una SELECTcon cualquier columna BLOB, siempre tendrá acceso al disco, mientras que sin BLOB tiene la oportunidad de obtener datos directamente de la RAM (la base de datos de alto rendimiento se optimizará para adaptarse a las tablas en la RAM);
  • la replicación será lenta, la demora de replicación será alta, ya que tendrá que empujar BLOB a esclavos. Un alto retraso en la replicación causará todo tipo de condiciones de carrera y otros problemas de sincronización, a menos que lo tome en cuenta explícitamente;
  • Las copias de seguridad / restauración de la base de datos tardarán mucho más;

Ventaja de velocidad: ¡ ninguna ! Si bien algunos sistemas de archivos más antiguos no manejarían bien los directorios con millones de archivos, los más modernos no tienen ningún problema y de hecho usan el mismo tipo de estructuras de datos que los BD (generalmente B-trees). Por ejemplo, ext4 (sistema de archivos predeterminado de Linux) usa Htree .

Conclusión: obstaculizará el rendimiento de su base de datos y no mejorará el rendimiento de recuperación de archivos.

Además, dado que está hablando de aplicaciones web, servir archivos estáticos directamente desde el sistema de archivos usando un servidor web moderno, lo que puede hacer sendfile()syscall es una tremenda mejora en el rendimiento. Por supuesto, esto no es posible si está recuperando archivos de DB. Considere, por ejemplo, este punto de referencia , que muestra a Ngnix haciendo 25K requisitos / s con 1000 conexiones simultáneas en una computadora portátil de gama baja. Ese tipo de carga freiría cualquier tipo de DB.

vartec
fuente
66
+1. Deje que su servidor web haga lo que mejor hace, sirviendo archivos desde el disco. No hagas que pregunte a PHP, ya que PHP tendrá que preguntar a MySQL, etc.
deizel
3
¿Cuándo aprenderán los programadores que el rendimiento no es todo lo que importa?
reinierpost
2
@reinierpost: lol. probablemente cuando tengamos especializaciones en artes liberales ;-)
vartec
1
@BillyONeal: ¿por qué supone que debe tener el mismo servidor para contenido estático y dinámico? En cuanto a la sincronización de archivos entre servidores, existen herramientas específicamente diseñadas para eso, mucho más eficientes que las bases de datos. Usar la base de datos como servidor de archivos es como tratar de clavar un clavo con un destornillador.
vartec
1
@BillyONeal: Estoy de acuerdo en que hay algunas "soluciones" en las que eso funcionaría, he visto muchas configuraciones de PHP amateur con imágenes en MySQL. Sin embargo, en una configuración de este tipo, una base de datos nunca admitirá tráfico alto que sirva BLOB.
vartec
18

Sería pragmático al respecto y seguiría el principio de "no optimizar aún". Haga la solución que tenga sentido en este momento, y una que tenga los recursos de desarrollo para implementar adecuadamente. Hay muchos problemas potenciales . Pero esos no necesariamente se convierten en problemas reales. Por ejemplo, probablemente no sería un problema si tienes 100 usuarios. Que podría ser un problema si usted tiene o 100.000 10.000.000 de usuarios. Pero en el último caso, debería haber una base para más recursos de desarrollo para hacer frente a todos los problemas.

Pero almacenar los datos en la base de datos lo alivia de tratar con otros problemas, por ejemplo, dónde deben almacenarse los archivos, cómo deben copiarse, etc. Dado que está escribiendo una aplicación web, sería una muy buena idea por razones de seguridad para asegurarse de que el proceso que aloja la aplicación no tenga acceso de escritura al sistema de archivos, por lo que debe configurar el servidor para que el proceso tenga acceso de lectura / escritura a la carpeta donde se almacenan los datos.

Yo personalmente elegiría almacenar los datos en la base de datos, pero asegúrese de que los BLOBS no se lean hasta que realmente se necesiten, es decir, no se ejecute "SELECT * FROM ..." en esas tablas que contienen blogs. Y me aseguraría de que el diseño facilite mover los datos de la base de datos al sistema de archivos, si tiene problemas de rendimiento. Por ejemplo, guarde la información del archivo en una tabla de archivos separada , manteniendo así la información del archivo lejos de otras entidades comerciales.

Suponiendo que tiene una clase de archivo para representar un archivo leído en la base de datos, el impacto de codificación de su posterior traslado será mínimo.

Pete
fuente
Esta es una excelente sugerencia. No empieces a resolver problemas que no tienes.
HeavyE
16

Microsoft lanzó un libro blanco sobre esto hace unos años. Se concentra en SqlServer, pero puede encontrar información interesante allí:

¿BLOB o no BLOB? Almacenamiento de objetos grandes en una base de datos o un sistema de archivos?

Una versión muy concisa de su conclusión es:

Al comparar el sistema de archivos NTFS y SQL Server 2005, los BLOBS más pequeños que 256KB son manejados más eficientemente por SQL Server, mientras que NTFS es más eficiente para BLOBS más grandes que 1MB.

Le recomendaría que escriba algunas pruebas pequeñas para su caso de uso particular. Tenga en cuenta que debe tener cuidado con los efectos de almacenamiento en caché. (¡Me sorprendió la primera vez que obtuve velocidades de guardar en disco que parecían tener mayores rendimientos de lo que era físicamente posible!)

Benjol
fuente
44
Debe saber que NTFS comienza a comportarse de manera muy errática cuando coloca más de ~ 100K archivos en un solo directorio. El acceso a los archivos se ralentiza bastante (al menos un orden de magnitud) y las operaciones de apertura de archivos comienzan a fallar (aparentemente) al azar. He experimentado este efecto en los sistemas Windows 2008 y Windows 7. Cuando redistribuí archivos entre múltiples directorios, todo volvió a la normalidad. No sé si la situación ha mejorado desde entonces.
Ferruccio
11

La vieja sabiduría convencional de almacenar archivos fuera de la base de datos podría dejar de mantenerse. Como cuestión de principio, favorecería la integridad sobre la velocidad, y con un DBMS moderno, puede tener ambos.

Tom Kyte parece estar de acuerdo :

No conozco ninguna ventaja para almacenar datos que quiero mantener durante mucho tiempo fuera de una base de datos.

Si está en la base de datos puedo

asegúrese de que sea administrado profesionalmente

respaldado

recuperable (con el resto de los datos)

asegurado

escalable (intente poner 100,000 documentos en un solo directorio, ahora, póngalos en la tabla, cuál 'escala', no es el directorio)

Puedo recuperar (flashback) fácilmente

Tengo bloqueo

He leído consistencia ...

Branko Dimitrijevic
fuente
8

Si.

Si sirve un archivo desde su sistema de archivos, su servidor web puede usar el código del kernel como sendfile () en BSD o Linux para copiar el archivo directamente al socket. Es muy rápido y muy eficiente.

Servir archivos fuera de la base de datos significa que tiene que copiar datos del disco del servidor de la base de datos a la memoria del servidor de la base de datos, luego de la memoria del servidor de db al puerto de red del servidor de db, luego de la red al proceso del servidor web, y luego nuevamente al conexión de red saliente.

A menos que tenga una buena razón para no hacerlo, siempre es mejor servir archivos estáticos desde el sistema de archivos.

Evan P.
fuente
Esto es cierto, pero no veo dónde dice el usuario en la pregunta que servirá archivos estáticos de la base de datos. Esto podría ser archivos dinámicos o archivos cargados por el usuario que, si se almacenan en el sistema de archivos separado de la base de datos, ahora deben sincronizarse y tener un proceso de copia de seguridad / restauración separado.
maple_shaft
1
Entiendo que la pregunta se trata de servir archivos cargados por el usuario. "Actualmente estoy creando una aplicación web que permite a los usuarios almacenar y compartir archivos [...] Me parece que almacenar los archivos en una base de datos [...]". No creo que sea realmente tan conveniente hacer volcados de base de datos con muchos blobs de varios megabytes en la base de datos. Además: sí, es difícil tratar con archivos; sincronizar, archivar, son todos más difíciles. Sin embargo, no es mucho más difícil, y sacrificar el rendimiento en línea para guardar algunas líneas en su script de copia de seguridad nocturno es un gran error.
Evan P.
5

El famoso Tom Kyte ha escrito que ellos (Oracle) están utilizando la base de datos Oracle como servidor de archivos y está funcionando perfectamente bien, incluso más rápido que el sistema de archivos normal, con plena transaccionalidad, sin pérdida de rendimiento y con una sola copia de seguridad.

Sí, pero tenga en cuenta que son los productores de Oracle DB, y para cualquier otro usuario hay problemas de costos. El uso de bases de datos comerciales como Oracle para el almacenamiento de archivos simplemente no es rentable.

Sin embargo, con PostgreSQL, por ejemplo, simplemente puede ejecutar otra instancia de base de datos solo para el almacenamiento de blobs. Entonces tiene soporte transaccional completo. Pero la transaccionalidad cuesta espacio DB. Existe la necesidad de una base de datos para almacenar múltiples instancias de blob para múltiples transacciones concurrentes. En PostgreSQL es lo más doloroso, ya que esta base de datos almacena los duplicados de blobs hechos para la transacción, incluso si ya no son necesarios, hasta que se complete el proceso VACUUM.

Con el almacenamiento del sistema de archivos, por otro lado, debe tener mucho cuidado cuando alguien modifica el archivo, porque la transacción puede revertirse y la copia del archivo debe mantenerse hasta que la versión anterior ya no sea visible.

En el sistema donde los archivos solo se agregan y eliminan, y el acceso transaccional a los archivos no es un problema, el almacenamiento del sistema de archivos será, en mi humilde opinión, la mejor opción.

Marinero danubiano
fuente
Hola, cuando dijiste "usar ... Oracle para el almacenamiento de archivos es simplemente ineficaz", ¿qué pasa si ya estamos usando Oracle para almacenar otros datos que no son de archivo? ¿Eso seguirá siendo un costo ineficaz?
Xiao Peng - ZenUML.com
RE: "debe ser muy cuidadoso cuando alguien modifica el archivo" ... como ex DBA de Oracle, tengo que sugerir que los archivos grandes se mantengan fuera de la base de datos y que nunca permita que se modifiquen. La gente comete errores. La única forma práctica de administrar la reversión (deshacer) de esos archivos es implementar un sistema Copy On Write para ellos. Todas las versiones se mantienen y archivan. El más antiguo se puede mover al almacenamiento remoto, procesar posteriormente para consolidar pequeños cambios en un archivo, etc.
DocSalvager
5

Por lo general, es mejor almacenar BLOB grandes en una tabla separada y simplemente mantener una referencia de clave externa al BLOB en su tabla principal. De esa manera, aún puede recuperar el archivo de la base de datos (por lo que no necesita ningún código especial) y evitar los problemas que rodean las dependencias externas de la base de datos (mantener sincronizada la base de datos y el sistema de archivos, etc.), pero solo incurre en esa sobrecarga si te unes explícitamente a esa tabla (o haces una llamada por separado). 10 MB no es terriblemente grande, la mayoría de las bases de datos comerciales modernas no tendrán problemas. La única razón por la que almacenaría un archivo en el sistema de archivos es para reducir el ancho de banda de la base de datos. Si su base de datos va a barajar muchos de estos archivos, entonces es posible que deba dividir la carga de trabajo y solo almacenar un descriptor de archivo de algún tipo. Entonces puede tener una llamada separada para cargar el archivo desde otro servidor,

TMN
fuente
4

Puede encontrarse con algunos de estos problemas:

  • Hacer lo SELECT *que implica la fila con el blob grande lleva mucho tiempo, incluso si no necesita el blob (por supuesto, debe hacer una selección específica, pero a veces las aplicaciones se escriben así)
  • Hacer una copia de seguridad puede llevar mucho más tiempo. Dependiendo de sus necesidades, es posible que deba bloquear sus tablas durante el tiempo de la copia de seguridad, por lo que es posible que desee mantener su tiempo de copia de seguridad bajo
  • La restauración también tomará mucho más tiempo.
  • Si se queda sin espacio, debe pensar de alguna manera (tal vez mover toda la base de datos a un nuevo servidor) para resolver este problema. Al almacenar los archivos en el sistema de archivos, siempre puede montar otro disco duro y establecer enlaces de software.
  • Simplemente buscar un archivo para depurar u otra información no es tan fácil. Esto también incluye scripts que pueden no tener acceso a la base de datos pero que necesitan información de varios archivos.

Por supuesto, también obtienes algunos beneficios:

  • Copia de seguridad de datos y menas de archivos están sincronizados
  • Eliminar el archivo sin que la base de datos lo sepa no es posible
  • No tiene que leer el archivo desde el disco, pero puede hacerlo en una declaración SQL
  • Puede descargar la base de datos, incluir el volcado en su entorno de desarrollo y tener todas las dependencias allí mismo

Personalmente no lo hago, ya que encuentro los contras mucho más pesados ​​que los profesionales. Pero como se indicó anteriormente, depende totalmente de su caso de uso y tal.

Sgoettschkes
fuente
1

Algunos sistemas de gestión de contenido de Enterpirse, como SiteCore, están utilizando una base de datos para almacenar datos de página y otra base de datos para almacenar archivos. Están usando MS SQL Server.

šljaker
fuente
¿Cómo responde esto a la pregunta que se hace?
mosquito
Si investiga un poco, descubrirá que SiteCore es uno de los sistemas de gestión de contenido empresarial más populares. SiteCore admite una gran cantidad de usuarios simultáneos y se escala bastante bien, por lo que sí, almacenar archivos dentro de una base de datos separada no es una mala práctica si lo hace correctamente.
šljaker
1

Para una implementación práctica, esto es lo que puede interesarle:

Benifits:

  1. Todo el contenido del archivo está definitivamente sincronizado con su tabla. Como dicen los comentarios anteriores, la copia de seguridad de los datos es totalmente conveniente ya que no es necesario mantener los datos sincronizados con el sistema de archivos.
  2. Desde la codificación, puede obtener el contenido del archivo directamente desde una selección SQL.
  3. Desde una consulta, incluso puede filtrar el contenido del archivo o su tamaño explícitamente desde la declaración SQL.

Desventajas:

  1. En comparación con una base de datos cuya estructura es semánticamente igual pero no almacena el contenido del archivo, su base de datos tiende a consumir radicalmente más memoria al hacer la consulta.
  2. La copia de seguridad automática puede causar problemas de rendimiento, pero no mucho. Imaginemos que su servidor de base de datos realiza copias de seguridad cada 6 horas y las bases de datos que tiene almacenan archivos de 10 MB por registro. Ese escenario no es lo que quieres.
PataoIngeniero Tao
fuente