É uma prática ruim armazenar arquivos grandes (10 MB) em um banco de dados?

188

Atualmente, estou criando um aplicativo da Web que permite aos usuários armazenar e compartilhar arquivos de 1 MB a 10 MB.

Parece-me que armazenar os arquivos em um banco de dados diminuirá significativamente o acesso ao banco de dados.

Será esta uma preocupação válida? É melhor armazenar os arquivos no sistema de arquivos e salvar o nome e o caminho do arquivo no banco de dados? Existem práticas recomendadas relacionadas ao armazenamento de arquivos ao trabalhar com um banco de dados?

Estou trabalhando em PHP e MySQL para este projeto, mas é o mesmo para a maioria dos ambientes ( Ruby on Rails , PHP , .NET ) e bancos de dados (MySQL, PostgreSQL ).

B Seven
fonte
9
Pergunta relacionada no DBA.SE: Arquivos - no banco de dados ou não?
Nick Chammas
11
Surpreso que ninguém postou a pesquisa MS feito sobre esta questão (para SQL Server 2008): Para BLOB ou não a BLOB: armazenamento de objetos grandes em um banco de dados ou um sistema de arquivos
Oded
2
grande é uma quantidade relativa, que eu (e muitas outras provavelmente) não vejo 10MBcomo grande em um sistema moderno.
27
Este tópico está de acordo com o FAQ - ele se encaixa nos marcadores "padrões de design" (antipatterns de barra) e "arquitetura de software". Por que foi fechado?
Izkata 31/05
21
Não vejo nenhuma imprecisão na questão como está agora. Eu não tenho idéia do por que foi fechado.
Reinierpost

Respostas:

139

Razões a favor do armazenamento de arquivos no banco de dados:

  1. Consistência de ACID, incluindo a reversão de uma atualização que é complicada quando os arquivos são armazenados fora do banco de dados. Isso não deve ser menosprezado. Ter os arquivos e o banco de dados sincronizados e capaz de participar de transações pode ser muito útil.
  2. Os arquivos acompanham o banco de dados e não podem ficar órfãos.
  3. Os backups incluem automaticamente os binários de arquivo.

Razão para armazenar arquivos no banco de dados:

  1. O tamanho de um arquivo binário difere entre os bancos de dados. No SQL Server, quando não estiver usando o objeto FILESTREAM, por exemplo, é 2 GB. Se os usuários precisarem armazenar arquivos maiores (como um filme, por exemplo), você terá que pular os bastidores para fazer a mágica acontecer.
  2. Aumenta o tamanho do banco de dados. Um conceito geral que você deve ter em mente: O nível de conhecimento necessário para manter um banco de dados aumenta proporcionalmente ao tamanho do banco de dados.Ou seja, bancos de dados grandes são mais complicados de manter do que bancos de dados pequenos. Armazenar os arquivos no banco de dados pode torná-lo muito maior. Mesmo que digamos que um backup completo diário seria suficiente, com um tamanho de banco de dados maior, talvez você não consiga mais fazer isso. Você pode considerar colocar os arquivos em um grupo de arquivos diferente (se o banco de dados suportar isso), ajustar os backups para separar o backup dos dados do backup dos arquivos etc. Nenhuma dessas coisas é impossível de aprender, mas sim adicione complexidade à manutenção, o que significa custos para os negócios. Bancos de dados maiores também consomem mais memória enquanto tentam armazenar o máximo de dados possível na memória.
  3. A portabilidade pode ser uma preocupação se você usar recursos específicos do sistema, como o FILESTREAMobjeto do SQL Server, e precisar migrar para um sistema de banco de dados diferente.
  4. O código que grava os arquivos no banco de dados pode ser um problema. Uma empresa para quem eu consultei há poucas luas atrás em algum momento conectou um front-end do Microsoft Access ao servidor de banco de dados e usou a capacidade do Access de carregar "qualquer coisa" usando seu controle Ole Object. Mais tarde, eles mudaram para usar um controle diferente, que ainda contava com Ole. Muito depois, alguém alterou a interface para armazenar o binário bruto. Extrair aqueles objetos de Ole era um novo nível do inferno. Quando você armazena arquivos no sistema de arquivos, não há uma camada adicional envolvida para quebrar / ajustar / alterar o arquivo de origem.
  5. É mais complicado exibir os arquivos em um site. Para fazer isso com colunas binárias, você precisa escrever um manipulador para transmitir o arquivo binário do banco de dados. Você também pode fazer isso, mesmo que armazene caminhos de arquivo, mas não precise fazer isso. Novamente, adicionar um manipulador não é impossível, mas adiciona complexidade e é outro ponto de falha.
  6. Você não pode tirar proveito do armazenamento em nuvem. Suponha que um dia você queira armazenar seus arquivos em um bucket do Amazon S3. Se o que você armazena no banco de dados são caminhos de arquivo, você pode alterá-los para caminhos no S3. Tanto quanto sei, isso não é possível em nenhum cenário com nenhum DBMS.

Na IMO, considerar o armazenamento de arquivos no banco de dados ou não como "ruim" requer mais informações sobre as circunstâncias e os requisitos. O tamanho e / ou número de arquivos sempre serão pequenos? Não há planos para usar o armazenamento em nuvem? Os arquivos serão veiculados em um site ou em um executável binário como um aplicativo do Windows?

Em geral, minha experiência constatou que armazenar caminhos é mais barato para as empresas, mesmo levando em conta a falta de ACID e a possibilidade de órfãos. No entanto, isso não significa que a Internet não seja uma legião com histórias de falta de controle de ACIDs que dão errado no armazenamento de arquivos, mas significa que, em geral, essa solução é mais fácil de construir, entender e manter.

Thomas
fonte
Por que você não pode usar CDNs? Este é um cenário suportado com praticamente todos os CDN que eu já ouvi falar.
Billy ONeal
@ Billyilly - Você não pode usar uma CDN e armazenar o arquivo no banco de dados. A menos que você esteja bem com a duplicação, não poderá ter as duas.
30512 Thomas
3
Erm, todo o ponto de uma CDN é duplicação. As CDNs apenas armazenam em cache o destino de um endereço da Web - o único requisito é que haja um host HTTP atendendo o conteúdo e que o conteúdo mude raramente. (Como na terra é o CDN deveria dizer onde você tirou a imagem de qualquer maneira?)
Billy ONeal
3
@ BillyONeal - No entanto, acho que essa é uma má escolha de palavras da minha parte e ajustei minha resposta. Especificamente, se você quiser usar o armazenamento em nuvem (e talvez usar uma CDN com seu armazenamento em nuvem), não poderá fazê-lo nativamente com a solução de armazenamento de banco de dados. Você precisaria escrever uma rotina de sincronização para extrair os arquivos do banco de dados e enviá-los ao seu provedor de armazenamento em nuvem.
30512 Thomas
@ BillyONeal - De certa forma, seu comentário foi a melhor resposta. Você pode ter todos os benefícios do armazenamento em banco de dados, mas nenhum dos problemas.
B Sete
89

Em muitos casos, isso é uma má ideia. Ele inchará os arquivos do banco de dados e causará vários problemas de desempenho. Se você colocar os blobs em uma tabela com um grande número de colunas, é ainda pior.

Contudo! Alguns bancos de dados, como o SQL Server, têm um tipo de coluna FILESTREAM. Nesse caso, seus dados são realmente armazenados em um arquivo separado no servidor de banco de dados e apenas um ID para o arquivo é salvo na tabela. Nesse caso, não vejo muitas razões para não manter os dados no servidor SQL. Os arquivos são incluídos automaticamente como parte do backup do servidor, e o banco de dados e os arquivos nunca estão fora de sincronia. O problema com a sugestão de Tony de armazenar nomes de arquivos é que o banco de dados e o sistema de arquivos podem ficar fora de sincronia. O banco de dados alegará que um arquivo existe quando foi excluído no disco. Se um processo estiver modificando o banco de dados e depois travar, os arquivos e o banco de dados não corresponderão (ou seja, nenhum ACID com arquivos fora de um banco de dados).

Timothy Baldridge
fonte
21
Não concordo com a declaração `Se um processo estiver modificando o banco de dados e depois travar, os arquivos e o banco de dados não corresponderão '. quando algo dá errado, é muito fácil mantê-los sincronizados.
Briddums 29/05
3
Eu estou com briddums nisso: considere o cenário: armazene o arquivo no sistema de arquivos (sem excluir o antigo), atualize o DB, com sucesso, exclua o arquivo antigo, na reversão, exclua o novo arquivo. Pior cenário - se o processo for interrompido, você terá um arquivo órfão. Mas você sempre tem os arquivos referenciados pelo DB na versão correta.
vartec 29/05
2
Outros problemas em potencial com o método File / DB: 1) você precisa fazer atualizações como cópia na gravação. Se o seu processo travar durante uma atualização, o status do banco de dados será revertido, o arquivo não será. 2) Isso exige algum tipo de coleta de lixo do arquivo antigo. 3) Armazenar tudo no banco de dados significa que as versões do banco de dados e dos arquivos estão sincronizadas após os backups. Restaure seu banco de dados para o estado há 2 semanas ... agora, onde está o conteúdo dos arquivos naquele momento?
Timothy Baldridge
3
@briddums - Não, pois o SQL Server se integra diretamente ao sistema de arquivos e gerencia esses arquivos em nome do sistema operacional. Eu não os usei, mas a documentação faz com que pareça FILESTREAM e suas FileTables descendentes garantem o melhor dos dois mundos: os arquivos são vinculados firmemente ao banco de dados e aos dados relacionados (permitindo que você gerencie centralmente os dados) sem inchar o base de dados.
Nick Chammas
11
Eu concordo com o Nick. Substituímos nosso sistema Disk + DB por colunas FILESTREAM e nunca mais olhamos para trás. É muito bom poder ter arquivos vinculados a outras tabelas via FKs. Portanto, você pode realmente dizer "cada pessoa deve ter um ou mais documentos de RH associados a ela" ou algo assim.
Timothy Baldridge
35

Sim, é uma má prática.

Impacto no desempenho no banco de dados:

  • se você fizer um SELECTcom qualquer coluna BLOB, sempre fará um acesso ao disco, enquanto sem os BLOBs você terá a chance de obter dados diretamente da RAM (o banco de dados de alto rendimento será otimizado para ajustar as tabelas na RAM);
  • a replicação será lenta, o atraso da replicação será alto, pois será necessário enviar BLOB aos escravos. O alto atraso de replicação causará todos os tipos de condições de corrida e outros problemas de sincronização, a menos que você leve isso em consideração;
  • Os backups / restauração do banco de dados levarão muito mais tempo;

Vantagem de velocidade - nenhuma ! Enquanto alguns sistemas de arquivos mais antigos não lidam bem com diretórios com milhões de arquivos, a maioria dos modernos não tem nenhum problema e, na verdade, usa o mesmo tipo de estrutura de dados que os BDs (geralmente árvores B). Por exemplo, ext4 (sistema de arquivos Linux padrão) usa Htree .

Conclusão: isso prejudicará o desempenho do seu banco de dados e não melhorará o desempenho da recuperação de arquivos.

Além disso, como você está falando sobre aplicativos da Web - servir arquivos estáticos diretamente do sistema de arquivos usando o servidor da web moderno, o que pode fazer o sendfile()syscall é uma tremenda melhoria de desempenho. Obviamente, isso não é possível se você estiver buscando arquivos do DB. Considere, por exemplo, esse benchmark , mostrando o Ngnix executando 25K req / s com 1000 conexões simultâneas em um laptop de baixo custo. Esse tipo de carga fritaria qualquer tipo de banco de dados.

vartec
fonte
6
+1. Deixe seu servidor da Web fazer o que é melhor, servindo arquivos do disco. Não fazê-lo pedir PHP, como PHP terá que pedir MySQL, etc.
deizel
3
Quando os programadores aprenderão que o desempenho não é tudo o que importa?
Reinierpost
2
@reinierpost: lol. Provavelmente quando chegarmos majors artes liberais ;-)
vartec
11
@ BillyONeal: por que você acha que precisa ter o mesmo servidor para conteúdo estático e dinâmico? Quanto à sincronização de arquivos entre servidores, existem ferramentas projetadas especificamente para isso, muito mais eficientes que os bancos de dados. Usar banco de dados como servidor de arquivos é como tentar martelar um prego com uma chave de fenda.
Vartec 31/05
11
@ Billyilly: Eu concordo que existem algumas "soluções" em que isso funcionaria. Eu já vi muitas configurações amadores de PHP com imagens no MySQL. No entanto, nessa configuração, um banco de dados nunca suporta BLOBs de alto tráfego.
Vartec
18

Eu seria pragmático e seguiria o princípio "não otimize ainda". Faça a solução que faz sentido no momento e uma que você tenha os recursos de desenvolvimento para implementar adequadamente. Existem muitos problemas em potencial . Mas esses não se tornam necessariamente problemas reais. Por exemplo, provavelmente não seria um problema se você tiver 100 usuários. Ele pode ser um problema se você tem 100.000 ou 10.000.000 usuários. Porém, no último caso, deve haver uma base para mais recursos de desenvolvimento para lidar com todos os problemas.

Mas armazenar os dados no banco de dados impede que você lide com outros problemas, por exemplo, onde os arquivos devem ser armazenados, como devem ser copiados, etc. Como você está escrevendo um aplicativo da Web, seria uma boa idéia por motivos de segurança. para garantir que o processo que hospeda o aplicativo não tenha acesso de gravação ao sistema de arquivos, você deve configurar o servidor para que o processo tenha acesso de leitura / gravação à pasta em que os dados estão armazenados.

Eu pessoalmente escolheria armazenar os dados no banco de dados, mas certifique-se de que os BLOBS não sejam lidos até que sejam realmente necessários, ou seja, nenhum "SELECT * FROM ..." executado nessas tabelas que contêm blogs. E eu me certificaria de que o design facilite a transferência dos dados do banco de dados para o sistema de arquivos, se você tiver problemas de desempenho. Por exemplo, armazene as informações do arquivo em uma tabela de arquivos separada , mantendo as informações do arquivo afastadas de outras entidades comerciais.

Supondo que você tenha uma classe File para representar um arquivo lido no banco de dados, o impacto da codificação da sua saída posterior será mínimo.

Pete
fonte
Esta é uma excelente sugestão. Não comece a resolver problemas que não possui.
HeavyE
16

A Microsoft lançou um white paper sobre isso alguns anos atrás. Ele se concentra no SqlServer, mas você pode encontrar algumas informações interessantes:

BLOB ou não BLOB? Armazenamento de Objetos Grandes em um Banco de Dados ou Sistema de Arquivos?

Uma versão muito concisa de sua conclusão é:

Ao comparar o sistema de arquivos NTFS e o SQL Server 2005, os BLOBS menores que 256 KB são tratados com mais eficiência pelo SQL Server, enquanto o NTFS é mais eficiente para os BLOBS maiores que 1 MB.

Eu recomendaria que você escrevesse alguns pequenos testes para seu caso de uso específico. Lembre-se de que você deve tomar cuidado com os efeitos do cache. (Fiquei impressionado na primeira vez que obtive velocidades de salvamento em disco que pareciam ter taxas de transferência mais altas do que era fisicamente possível!)

Benjol
fonte
4
Você deve saber que o NTFS começa a se comportar de maneira muito irregular quando você coloca mais de ~ 100K arquivos em um único diretório. O acesso a arquivos diminui bastante (pelo menos uma ordem de magnitude) e as operações de abertura de arquivos começam a falhar (aparentemente) aleatoriamente. Eu experimentei esse efeito nos sistemas Windows 2008 e Windows 7. Quando redistribui arquivos entre vários diretórios, tudo voltou ao normal. Não sei se a situação melhorou desde então.
Ferruccio
11

A velha sabedoria convencional de armazenar arquivos fora do banco de dados pode não ser mais válida. Por uma questão de princípio, eu preferiria a integridade do que a velocidade e, com um DBMS moderno, você pode ter os dois.

Tom Kyte parece concordar :

Não conheço vantagens em armazenar dados que desejo manter por muito tempo fora de um banco de dados.

Se estiver no banco de dados eu posso

tenha certeza de que é gerenciado profissionalmente

backup

recuperável (com o restante dos dados)

seguro

escalável (tente colocar 100.000 documentos em um único diretório, agora, coloque-os na tabela - qual deles 'dimensiona' - não é o diretório)

Posso recuperar (flashback) facilmente

Eu tenho travamento

Eu li consistência ...

Branko Dimitrijevic
fonte
8

Sim.

Se você enviar um arquivo do seu sistema de arquivos, seu servidor Web poderá usar código do kernel como sendfile () no BSD ou Linux para copiar o arquivo diretamente no soquete. É muito rápido e muito eficiente.

A entrega de arquivos fora do banco de dados significa que você deve copiar os dados do disco do servidor de banco de dados para a memória do servidor de banco de dados, da memória do servidor db para a porta de rede do servidor db e, em seguida, da rede para o processo do servidor da Web e depois para o diretório conexão de rede de saída.

A menos que você tenha realmente um bom motivo para isso, é sempre melhor servir arquivos estáticos do sistema de arquivos.

Evan P.
fonte
Isso é verdade, mas não consigo ver onde o usuário afirma na pergunta que ele estará servindo arquivos estáticos do banco de dados. Isso pode muito bem ser arquivos dinâmicos ou arquivos carregados pelo usuário que, se armazenados no sistema de arquivos separados do banco de dados, agora devem ser sincronizados e ter um processo de backup / restauração separado.
maple_shaft
11
Meu entendimento é que a pergunta é sobre a veiculação de arquivos enviados por usuários. "Atualmente, estou criando um aplicativo da web que permite aos usuários armazenar e compartilhar arquivos [...] Parece-me que os arquivos são armazenados em um banco de dados [...]". Eu não acho que seja realmente tão conveniente fazer dumps de banco de dados com muitos blobs de megabytes no banco de dados. Além disso: sim, é difícil lidar com arquivos; sincronização, arquivamento são todos mais difíceis. No entanto, não é muito mais difícil, e sacrificar o desempenho online para salvar algumas linhas em seu script de backup noturno é um grande erro.
Evan P. #
5

O famoso Tom Kyte escreveu que eles (o Oracle) estão usando o banco de dados Oracle como servidor de arquivos e está funcionando perfeitamente, ainda mais rápido que o sistema de arquivos normal, com transacionalidade total, sem perda de desempenho e com backup único.

Sim, mas observe que eles são os produtores do banco de dados Oracle e, para qualquer outro usuário, há problemas de custo. O uso de banco de dados comercial, como o Oracle, para armazenamento de arquivos é simplesmente ineficaz.

No entanto, com o PostgreSQL, por exemplo, você pode simplesmente executar outra instância de banco de dados apenas para armazenamento de blob. Você tem suporte transacional completo. Mas a transacionalidade custa espaço no banco de dados. É necessário que o banco de dados armazene várias instâncias de blob para várias transações simultâneas. No PostgreSQL, é o mais doloroso, pois esse banco de dados armazena as duplicatas dos blobs feitos para a transação, mesmo que não sejam mais necessários, até que o processo VACUUM seja concluído.

Com o armazenamento do sistema de arquivos, por outro lado, você deve ter muito cuidado quando alguém modifica o arquivo, porque a transação pode ser revertida e a cópia do arquivo deve ser mantida até que a versão antiga não esteja mais visível.

No sistema em que os arquivos são adicionados e excluídos apenas, e o acesso transacional aos arquivos não é um problema, o armazenamento do sistema de arquivos será IMHO a melhor opção.

Marinheiro Danubiano
fonte
Olá, quando você disse que "usar ... o Oracle para armazenamento de arquivos é simplesmente ineficaz em termos de custo", e se já estivermos usando o Oracle para armazenar outros dados que não são arquivos? Isso ainda terá um custo ineficaz?
Xiao Peng - ZenUML.com
RE: "você deve ter muito cuidado quando alguém modifica o arquivo" ... como um antigo DBA do Oracle, tenho que sugerir que arquivos grandes sejam mantidos fora do banco de dados e que você nunca permita que os arquivos sejam modificados. Pessoas cometem erros. A única maneira prática de gerenciar a reversão (desfazer) desses arquivos é implementar um sistema Copy On Write para eles. Todas as versões são mantidas e arquivadas. O mais velho pode ser movido para fora para armazenamento remoto, cargo processado para consolidar pequenas alterações em um arquivo, etc.
DocSalvager
5

Geralmente, é melhor armazenar BLOBs grandes em uma tabela separada e manter uma referência de chave estrangeira ao BLOB em sua tabela principal. Dessa forma, você ainda pode recuperar o arquivo do banco de dados (para não precisar de nenhum código especial) e evitar os problemas que envolvem as dependências externas do banco de dados (mantendo o banco de dados e o sistema de arquivos sincronizados, etc.), mas apenas incorre nessa sobrecarga. se você ingressar explicitamente nessa tabela (ou fazer uma chamada separada). 10 MB não é muito grande, a maioria dos bancos de dados comerciais modernos não terá problemas. A única razão pela qual eu armazenaria um arquivo no sistema de arquivos é reduzir a largura de banda do banco de dados. Se seu banco de dados embaralha muitos desses arquivos, talvez seja necessário dividir a carga de trabalho e armazenar apenas um descritor de arquivo de algum tipo. Em seguida, você pode ter uma chamada separada para carregar o arquivo de outro servidor,

TMN
fonte
4

Você pode ter alguns destes problemas:

  • Fazer um SELECT *que envolva a linha com o blob grande leva muito tempo, mesmo que você não precise do blob (é claro que você deve fazer uma seleção específica, mas às vezes os aplicativos são escritos assim)
  • Fazer um backup pode demorar muito mais. Dependendo das suas necessidades, pode ser necessário bloquear suas tabelas durante o horário do backup, portanto, você deve manter o tempo de backup baixo
  • A restauração também levará muito mais tempo.
  • Se você ficar sem espaço, precisará pensar em alguma maneira (talvez movendo o banco de dados inteiro para um novo servidor) para resolver esse problema. Armazenando os arquivos no sistema de arquivos, você sempre pode montar outro disco rígido e definir links flexíveis.
  • Simplesmente procurar um arquivo para depuração ou outras informações não é tão fácil. Isso também inclui scripts que podem não ter acesso ao banco de dados, mas precisam de algumas informações de vários arquivos.

Claro que você também recebe alguns benefícios:

  • Fazendo backup de dados e arquivos como eles estão sincronizados
  • Remover o arquivo sem o conhecimento do banco de dados não é possível
  • Você não precisa ler o arquivo do disco, mas pode fazê-lo em uma instrução sql
  • Você pode baixar o banco de dados, incluir o despejo em seu ambiente de desenvolvimento e ter todas as dependências ali

Pessoalmente, não faço isso porque acho os contras muito mais pesados ​​que os profissionais. Mas, como mencionado acima, depende totalmente do seu caso de uso e tal.

Sgoettschkes
fonte
1

Alguns sistemas de gerenciamento de conteúdo da Enterpirse, como o SiteCore, estão usando um banco de dados para armazenar dados da página e outro banco de dados para armazenar arquivos. Eles estão usando o MS SQL Server.

šljaker
fonte
Como isso responde à pergunta?
Gnat
Se você pesquisar um pouco, descobrirá que o SiteCore é um dos sistemas de gerenciamento de conteúdo corporativo mais populares. O SiteCore suporta grande número de usuários simultâneos e dimensiona muito bem; portanto, armazenar arquivos dentro de um banco de dados separado não é uma prática ruim, se você fizer isso corretamente.
šljaker
1

Para implementação prática, eis o que você pode interessar:

Benefícios:

  1. Todo o conteúdo do arquivo é definitivamente sincronizado com a sua tabela. Como os comentários acima disseram, o backup de dados é totalmente conveniente, pois você não precisa manter os dados sincronizados com o sistema de arquivos.
  2. Na codificação, você pode obter o conteúdo do arquivo diretamente de uma seleção SQL.
  3. Em uma consulta, você pode até filtrar explicitamente o conteúdo do arquivo ou seu tamanho a partir da instrução SQL.

Desvantagens:

  1. Comparado a um banco de dados cuja estrutura é semanticamente a mesma, mas não armazena o conteúdo do arquivo, o banco de dados tende a consumir radicalmente mais memória ao fazer uma consulta.
  2. O backup automático pode causar problemas de desempenho, mas não muito. Vamos imaginar que seu servidor de banco de dados esteja fazendo backup das coisas a cada 6 horas e os bancos de dados que você possui estão armazenando arquivos de 10 MB por registro. Esse cenário não é o que você deseja.
PataoEngineer Tao
fonte