Это плохая практика для хранения больших файлов (10 МБ) в базе данных?

188

В настоящее время я создаю веб-приложение, которое позволяет пользователям хранить и обмениваться файлами размером от 1 до 10 МБ.

Мне кажется, что хранение файлов в базе данных значительно замедлит доступ к базе данных.

Это действительная проблема? Лучше ли хранить файлы в файловой системе и сохранять имя файла и путь в базе данных? Есть ли рекомендации по хранению файлов при работе с базой данных?

Я работаю в PHP и MySQL для этого проекта, но эта проблема одинакова для большинства сред ( Ruby on Rails , PHP , .NET ) и баз данных (MySQL, PostgreSQL ).

Б Семерка
источник
9
Связанный вопрос по DBA.SE: Файлы - в базе данных или нет?
Ник Чаммас
11
Удивлен, что никто не опубликовал исследование MS, выполненное по этой проблеме (для SQL Server 2008): « BLOB или BLOB: хранение больших объектов в базе данных или файловой системе»
Одед
2
большое - относительная величина, я (и, возможно, многие другие) не вижу 10MBтакой большой в современной системе.
27
Это часто встречается в соответствии с часто задаваемыми вопросами - оно подходит под маркеры «шаблоны проектирования» («косая черта») и «архитектура программного обеспечения». Почему это было закрыто?
Изката
21
Я не вижу никакой неопределенности в этом вопросе, как сейчас. Я понятия не имею, почему это было закрыто.
reinierpost

Ответы:

139

Причины в пользу хранения файлов в базе данных:

  1. Согласованность ACID, включая откат обновления, который усложняется, когда файлы хранятся вне базы данных. Это не должно быть слегка приукрашено. Синхронизация файлов и базы данных и возможность участвовать в транзакциях может быть очень полезным.
  2. Файлы идут с базой данных и не могут быть потеряны из нее.
  3. Резервные копии автоматически включают двоичные файлы.

Причина против хранения файлов в базе данных:

  1. Размер двоичного файла отличается в разных базах данных. На SQL Server, например, если не используется объект FILESTREAM, он равен 2 ГБ. Если пользователям нужно хранить файлы большего размера (например, в фильме), вы должны прыгать через обручи, чтобы это волшебство произошло.
  2. Увеличивает размер базы данных. Одна общая концепция, которую вы должны принять близко к сердцу: уровень знаний, необходимый для ведения базы данных, увеличивается пропорционально размеру базы данных.То есть, большие базы данных более сложны в обслуживании, чем маленькие базы данных. Хранение файлов в базе данных может сделать базу данных намного больше. Даже если, скажем, было бы достаточно ежедневного полного резервного копирования с большим размером базы данных, вы больше не сможете этого делать. Возможно, вам придется подумать о том, чтобы поместить файлы в другую файловую группу (если база данных это поддерживает), настроить резервные копии, чтобы отделить резервную копию данных от резервной копии файлов и т. Д. Ни одна из этих вещей не может быть изучена, но усложнить обслуживание, что означает стоимость для бизнеса. Большие базы данных также потребляют больше памяти, так как они пытаются вставить как можно больше данных в память.
  3. Переносимость может быть проблемой, если вы используете системные функции, такие как FILESTREAMобъект SQL Server, и вам необходимо перейти на другую систему базы данных.
  4. Код, который записывает файлы в базу данных, может быть проблемой. Одна компания, с которой я консультировался не так много месяцев назад, в какой-то момент подключила интерфейс Microsoft Access к своему серверу базы данных и использовала возможность Access загружать «что угодно», используя свой элемент управления Ole Object. Позже они изменили использовать другой элемент управления, который все еще полагался на Оле. Намного позже кто-то изменил интерфейс для хранения необработанного двоичного файла. Извлечение этих Оле Объектов было новым уровнем ада. Когда вы храните файлы в файловой системе, для обертывания / подстройки / изменения исходного файла не требуется дополнительный слой.
  5. Сложнее обслуживать файлы на веб-сайте. Чтобы сделать это с двоичными столбцами, вы должны написать обработчик для потоковой передачи двоичного файла из базы данных. Вы также можете сделать это, даже если вы храните пути к файлам, но вам не нужно это делать. Опять же, добавление обработчика не является невозможным, но добавляет сложности и является еще одной точкой отказа.
  6. Вы не можете воспользоваться преимуществами облачного хранилища. Предположим, однажды вы захотите сохранить свои файлы в корзине Amazon S3. Если то, что вы храните в базе данных, это пути к файлам, вам предоставляется возможность изменить их на пути на S3. Насколько я знаю, это невозможно в любом сценарии с любой СУБД.

ИМО, считая хранение файлов в базе данных или нет как «плохое», требует больше информации об обстоятельствах и требованиях. Размер и / или количество файлов всегда будут маленькими? Нет ли планов использовать облачное хранилище? Будут ли файлы размещены на веб-сайте или в двоичном исполняемом файле, например, в приложении Windows?

В целом, мой опыт показал, что хранение путей обходится бизнесу дешевле, даже если учесть отсутствие ACID и вероятность сирот. Тем не менее, это не означает, что Интернет не легион с историями об отсутствии контроля ACID с ошибками в хранении файлов, но это означает, что в целом такое решение легче построить, понять и поддерживать.

Томас
источник
Почему вы не можете использовать CDN? Это поддерживаемый сценарий практически со всеми CDN, о которых я когда-либо слышал.
Билли ОНил
@BillyONeal - Вы не можете использовать CDN и сохранить файл в базе данных. Если вы не в порядке с дублированием, вы не можете иметь оба.
Томас
3
Хм, весь смысл CDN является дублирование. CDN просто кэшируют цель веб-адреса - единственное требование - наличие хоста HTTP, обслуживающего контент, и контент редко меняется. (Как, черт возьми, CDN должен сообщать, откуда вы взяли изображение?)
Billy ONeal,
3
@BillyONeal - Тем не менее, я думаю, что это плохой выбор слов с моей стороны, и я исправил свой ответ. В частности, если вы хотите использовать облачное хранилище (а затем, возможно, использовать CDN с облачным хранилищем), вы не можете сделать это изначально с решением для хранения базы данных. Вам нужно будет написать процедуру синхронизации, чтобы извлечь файлы из базы данных и затем отправить их поставщику облачного хранилища.
Томас
@BillyONeal - В некотором смысле, ваш комментарий был лучшим ответом. Вы можете иметь все преимущества хранения БД, но ни одна из проблем.
B 7
89

Во многих случаях это плохая идея. Это раздувает файлы базы данных и вызывает несколько проблем с производительностью. Если вы поместите капли в таблицу с большим количеством столбцов, это будет еще хуже.

Тем не мение! Некоторые базы данных, такие как SQL Server, имеют тип столбца FILESTREAM. В этом случае ваши данные фактически хранятся в отдельном файле на сервере базы данных, и в таблице сохраняется только идентификатор файла. В этом случае я не вижу особой причины не хранить данные на сервере SQL. Файлы автоматически включаются как часть резервной копии сервера, а база данных и файлы никогда не синхронизируются. Проблема с предложением Тони хранить имена файлов заключается в том, что база данных и файловая система могут быть не синхронизированы. База данных будет утверждать, что файл существует, когда он был удален на диске. Если процесс изменяет базу данных, а затем происходит сбой, файлы и база данных не будут совпадать (т. Е. Нет ACID с файлами вне базы данных).

Тимоти Болдридж
источник
21
Я не согласен с утверждением «Если процесс изменяет БД, а затем происходит сбой, файлы и БД не будут совпадать». Если вы заверните весь процесс в транзакцию (создайте файл, проверьте файл, обновите БД) и выбросите сообщения об ошибках когда что-то идет не так, очень просто поддерживать их синхронизацию.
briddums
3
Я с briddums на это: рассмотрим сценарий: сохранить файл в файловой системе (без удаления старой), обновить БД, при успешном удалении старого файла, при откате удалить новый файл. В худшем случае - если процесс прерывается, у вас есть файл-сирота. Но у вас всегда есть файлы, на которые ссылается БД в правильной версии.
vartec
2
Другие потенциальные проблемы с методом File / DB: 1) вы должны выполнять обновления как копирование при записи. Если во время обновления произойдет сбой вашего процесса, состояние БД будет откатано, файл не будет. 2) Для этого требуется какая-то сборка мусора старого файла. 3) Хранение всего в БД означает, что версии БД и файлов синхронизируются после резервного копирования. Восстановите вашу БД в ее состояние 2 недели назад ... что теперь, где содержимое файлов в то время?
Тимоти Болдридж
3
@briddums - Нет, поскольку SQL Server интегрируется непосредственно в файловую систему и управляет этими файлами от имени ОС. Я сам ими не пользовался, но из документации видно, что FILESTREAM и его потомки FileTables предоставляют вам лучшее из обоих миров: файлы тесно связаны с базой данных и связывают данные (что позволяет централизованно управлять вашими данными) без вздутия база данных.
Ник Чаммас
1
Я согласен с Ником. Мы заменили нашу систему Disk + DB колонками FILESTREAM и никогда не оглядывались назад. Очень приятно иметь возможность связывать файлы с другими таблицами через FK. Таким образом, вы можете сказать: «Каждый человек должен иметь один или несколько документов по персоналу, связанных с ними», или что-то подобное.
Тимоти Болдридж
35

Да, это плохая практика.

Влияние производительности на БД:

  • если вы делаете SELECTс любым столбцом BLOB, вы всегда будете осуществлять доступ к диску, в то время как без BLOB у вас будет возможность получать данные прямо из ОЗУ (БД с высокой пропускной способностью будет оптимизирована для размещения таблиц в ОЗУ);
  • Репликация будет медленной, задержка репликации высока, так как придется передавать BLOB на ведомые устройства. Высокая задержка репликации будет вызывать всевозможные условия гонки и другие проблемы с синхронизацией, если вы явно не учли это;
  • Резервное копирование / восстановление БД займет намного больше времени;

Преимущество в скорости - нет ! В то время как некоторые старые файловые системы не справляются с хорошими каталогами с миллионами файлов, большинство современных вообще не имеют проблем и фактически используют структуры данных того же типа, что и BD (обычно B-деревья). Например, ext4 (файловая система Linux по умолчанию) использует Htree .

Вывод: это снизит производительность вашей БД и не улучшит производительность поиска файлов.

Кроме того, поскольку вы говорите о веб-приложении - подача статических файлов непосредственно из файловой системы с использованием современного веб-сервера, которая может выполнять sendfile()syscall, является огромным улучшением производительности. Это, конечно, невозможно, если вы извлекаете файлы из БД. Рассмотрим, например, этот тест , показывающий, что Ngnix выполняет 25K запросов / с с 1000 одновременных подключений на ноутбуке нижнего уровня. Такая нагрузка поджарит любую БД.

Vartec
источник
6
+1. Пусть ваш веб-сервер делает то, что он делает лучше всего, обслуживая файлы с диска. Не заставляйте его спрашивать PHP, так как PHP должен будет спрашивать MySQL и т. Д.
deizel
3
Когда программисты узнают, что производительность не так уж важна?
reinierpost
2
@reinierpost: лол. вероятно, когда мы получим специальности гуманитарных наук ;-)
vartec
1
@BillyONeal: почему вы предполагаете, что у вас должен быть один и тот же сервер для статического и динамического контента? Что касается синхронизации файлов между серверами, то есть инструменты, специально разработанные для этого, гораздо более эффективные, чем базы данных. Использование базы данных в качестве файлового сервера похоже на попытку забить гвоздь отверткой.
vartec
1
@BillyONeal: я согласен, что есть некоторые «решения», где это будет работать, я видел довольно много любительских установок PHP с изображениями в MySQL. Однако при такой установке БД никогда не будет поддерживать большой объем трафика, обслуживающий большие двоичные объекты.
vartec
18

Я был бы прагматичен в этом и следовал бы принципу «пока не оптимизировать». Сделайте решение, которое имеет смысл на данный момент, и такое, которое у вас есть ресурсы для разработки, чтобы правильно реализовать. Есть много потенциальных проблем . Но они не обязательно становятся реальными проблемами. Например, это не будет проблемой, если у вас есть 100 пользователей. Это может быть проблемой, если у вас есть 100 000 или 10 000 000 пользователей. Но в последнем случае должна быть основа для увеличения ресурсов на разработку для решения всех вопросов.

Но хранение данных в базе данных освобождает вас от решения других проблем, например, где следует хранить файлы, как их резервировать и т. Д. Поскольку вы пишете веб-приложение, это будет очень хорошая идея по соображениям безопасности. чтобы убедиться, что процесс, в котором размещено приложение, не имеет доступа на запись в файловую систему, вам необходимо настроить сервер таким образом, чтобы процесс имел доступ на чтение / запись к папке, в которой хранятся данные.

Я бы лично решил хранить данные в базе данных, но следите за тем, чтобы BLOBS не читались до тех пор, пока они действительно не потребуются, т.е. не выполнялось «SELECT * FROM ...» в тех таблицах, содержащих блоги. И я бы позаботился о том, чтобы дизайн облегчал перемещение данных из базы данных в файловую систему, если у вас возникают проблемы с производительностью. Например, храните информацию о файле в отдельной таблице файлов , таким образом сохраняя информацию о файле отдельно от других бизнес-объектов.

Предполагая, что у вас есть класс File для представления файла, считываемого в базе данных, влияние последующего перемещения на код будет минимальным.

Пит
источник
Это отличное предложение. Не начинайте решать проблемы, которых у вас нет.
HeavyE
16

Microsoft выпустила официальный документ об этом несколько лет назад. Он концентрируется на SqlServer, но там вы можете найти некоторую интересную информацию:

BLOB или не BLOB? Хранение больших объектов в базе данных или файловой системе?

Очень краткая версия их заключения:

При сравнении файловой системы NTFS и SQL Server 2005 большие двоичные объекты размером менее 256 КБ более эффективно обрабатываются SQL Server, а NTFS более эффективны для больших двоичных объектов размером более 1 МБ.

Я бы порекомендовал вам написать несколько небольших тестов для вашего конкретного случая использования. Имейте в виду, что вы должны остерегаться эффектов кэширования. (Я был поражен, когда впервые получил скорости сохранения на диск, которые, казалось, имели более высокую пропускную способность, чем это было физически возможно!)

Benjol
источник
4
Вы должны знать, что NTFS начинает работать очень хаотично, когда вы помещаете более 100 000 файлов в один каталог. Доступ к файлам значительно замедляется (по крайней мере, на порядок), и операции открытия файлов начинают проваливаться (по-видимому) случайным образом. Я испытал этот эффект в системах Windows 2008 и Windows 7. Когда я перераспределял файлы между несколькими каталогами, все возвращалось в нормальное состояние. Я не знаю, улучшилась ли ситуация с тех пор.
Ферруччо
11

Старая традиционная мудрость хранения файлов вне базы данных может больше не действовать. В принципе, я бы предпочел целостность, а не скорость, и с современной СУБД вы можете иметь и то, и другое.

Том Кайт, кажется, согласен :

Я не знаю никаких преимуществ для хранения данных, которые я хочу долгое время хранить вне базы данных.

Если это в базе данных, я могу

быть уверенным, что это профессионально

резервное копирование

восстанавливаемый (с остальными данными)

обеспеченный

масштабируемый (попробуйте поместить 100 000 документов в один каталог, теперь поместите их в таблицу, которая «масштабируется» - это не каталог)

Я могу легко восстановить (флэшбэк)

У меня есть блокировка

Я прочитал последовательность ...

Бранко Димитриевич
источник
8

Да.

Если вы обслуживаете файл из вашей файловой системы, ваш веб-сервер может использовать код ядра, такой как sendfile () в BSD или Linux, чтобы скопировать файл непосредственно в сокет. Это очень быстро и очень эффективно.

Обслуживание файлов из базы данных означает, что вам необходимо скопировать данные с диска сервера базы данных в память сервера базы данных, затем из памяти сервера базы данных в сетевой порт сервера базы данных, затем из сети в процесс веб-сервера, а затем снова в базу данных сервера. исходящее сетевое соединение.

Если у вас нет веской причины не делать этого, всегда лучше обслуживать статические файлы из файловой системы.

Эван П.
источник
Это правда, но я не вижу, где пользователь заявляет в вопросе, что он будет обслуживать статические файлы из базы данных. Это вполне могут быть динамические файлы или загруженные пользователем файлы, которые, если они хранятся в файловой системе отдельно от базы данных, теперь должны синхронизироваться и иметь отдельный процесс резервного копирования / восстановления.
maple_shaft
1
Насколько я понимаю, речь идет об обслуживании загруженных пользователем файлов. «В настоящее время я создаю веб-приложение, которое позволяет пользователям хранить и обмениваться файлами [...] Мне кажется, что хранение файлов в базе данных [...]». Я не думаю, что на самом деле так удобно делать дампы БД с большим количеством мегабайтных больших двоичных объектов в базе данных. Также: да, с файлами тяжело иметь дело; Синхронизация, архивирование, все сложнее. Тем не менее, это не намного сложнее, и жертвовать производительностью онлайн, чтобы сохранить несколько строк в скрипте ночного резервного копирования, является большой ошибкой.
Эван П.
5

Знаменитый Том Кайт написал, что они (Oracle) используют базу данных Oracle в качестве файлового сервера, и она прекрасно работает, даже быстрее, чем обычная файловая система, с полной транзакционностью, без потери производительности и с одним резервным копированием.

Да, но обратите внимание, что они являются производителем БД Oracle, и для любого другого пользователя существуют проблемы с ценами. Использование коммерческих БД, таких как Oracle, для хранения файлов просто неэффективно с точки зрения затрат.

Однако, например, в PostgreSQL вы можете просто запустить другой экземпляр БД только для хранения больших двоичных объектов. У вас есть полная поддержка транзакций. Но транзакционность стоит пространства БД. Существует необходимость в базе данных для хранения нескольких экземпляров BLOB-объектов для нескольких одновременных транзакций. В PostgreSQL это наиболее болезненно, поскольку в этой базе данных хранятся дубликаты BLOB-объектов, созданных для транзакции, даже если они больше не нужны, пока не будет завершен процесс VACUUM.

С другой стороны, с хранилищем файловой системы вы должны быть очень осторожны, когда кто-то изменяет файл, потому что транзакцию можно откатить, и копия файла должна храниться до тех пор, пока старая версия больше не будет видна.

В системе, где файлы только добавляются и удаляются, а транзакционный доступ к файлам не является проблемой, хранилище файловой системы будет ИМХО лучшим выбором.

Дунайский моряк
источник
Привет, когда вы сказали, что "использование ... Oracle для хранения файлов просто неэффективно", что если мы уже используем Oracle для хранения других нефайловых данных? Это все еще будет неэффективным с точки зрения затрат?
Сяо Пэн - ZenUML.com
RE: «Вы должны быть очень осторожны, когда кто-то изменяет файл» ... как бывший администратор базы данных Oracle, я должен предложить, чтобы большие файлы не попадали в базу данных, и чтобы вы никогда не позволяли файлам изменяться. Люди делают ошибки. Единственный практический способ управлять откатом (отменой) этих файлов - это внедрить для них систему копирования при записи. Таким образом, все версии поддерживаются и архивируются. Старейшие могут быть перемещены в удаленное хранилище,
постобработаны
5

Обычно лучше хранить большие большие двоичные объекты в отдельной таблице и просто сохранять ссылку на внешний ключ для большого двоичного объекта в основной таблице. Таким образом, вы все равно можете извлечь файл из базы данных (поэтому вам не нужен какой-либо специальный код), и вы избежите проблем, связанных с зависимостями от внешних БД (синхронизация БД и файловой системы и т. Д.), Но вы только понесете эти издержки. если вы явно присоединитесь к этой таблице (или сделаете отдельный вызов). 10 МБ не очень большие, у большинства современных коммерческих баз данных проблем не будет. Единственная причина, по которой я бы сохранил файл в файловой системе - это сокращение пропускной способности базы данных. Если ваша база данных будет перетасовывать много этих файлов, то вам может потребоваться разделить рабочую нагрузку и сохранить только дескриптор файла какого-либо типа. Затем вы можете сделать отдельный вызов для загрузки файла с другого сервера,

TMN
источник
4

Вы можете столкнуться с некоторыми из этих проблем:

  • Выполнение, SELECT *которое включает в себя строку с большим BLOB-объектом, занимает очень много времени, даже если вам не нужен BLOB-объект (Конечно, вы должны сделать определенный выбор, но иногда приложения пишутся так)
  • Создание резервной копии может занять гораздо больше времени. В зависимости от ваших потребностей вам может потребоваться заблокировать ваши таблицы на время резервного копирования, поэтому вы можете захотеть сохранить время резервного копирования низким
  • Восстановление также займет гораздо больше времени.
  • Если у вас не хватает места, вам нужно придумать какой-то способ (возможно, перенести всю базу данных на новый сервер), чтобы решить эту проблему. Храня файлы в файловой системе, вы всегда можете смонтировать другой жесткий диск и установить программные ссылки.
  • Просто найти файл для отладки или другой информации не так просто. Это также включает сценарии, которые могут не иметь доступа к базе данных, но нуждаются в некоторой информации из различных файлов.

Конечно, вы также получаете некоторые преимущества:

  • Резервное копирование данных и файлов меню они синхронизированы
  • Удаление файла без базы данных невозможно
  • Вам не нужно читать файл с диска, но вы можете сделать это одним оператором sql
  • Вы можете загрузить базу данных, включить дамп в свою среду разработки и сразу же получить все зависимости

Лично я не делаю это, поскольку нахожу минусы намного тяжелее, чем плюсы. Но, как указано выше, это полностью зависит от вашего варианта использования и тому подобное.

Sgoettschkes
источник
1

Некоторые системы управления контентом Enterpirse, такие как SiteCore, используют одну базу данных для хранения данных страницы и другую базу данных для хранения файлов. Они используют MS SQL Server.

šljaker
источник
как это отвечает на заданный вопрос?
комнат
Если вы проведете небольшое исследование, вы обнаружите, что SiteCore является одной из самых популярных систем управления корпоративным контентом. SiteCore поддерживает большое количество одновременно работающих пользователей и довольно хорошо масштабируется, поэтому, если вы делаете это правильно, хранение файлов в отдельной базе данных не является плохой практикой.
Шлякер
1

Для практической реализации, вот что вы можете касаться:

ПРЕИМУЩЕСТВА:

  1. Все содержимое файла определенно синхронизировано с вашей таблицей. Как сказано выше, резервное копирование данных абсолютно удобно, поскольку вам не нужно синхронизировать данные с файловой системой.
  2. Из кодирования вы можете получить содержимое файла непосредственно из SQL-выбора.
  3. Из запроса можно даже явно фильтровать содержимое файла или его размер из оператора SQL.

Недостатки:

  1. По сравнению с базой данных, структура которой семантически одинакова, но не хранит содержимое файла, ваша база данных имеет тенденцию к радикальному увеличению памяти при выполнении запроса.
  2. Автоматическое резервное копирование может вызвать проблемы с производительностью, но не сильно. Давайте представим, что ваш сервер баз данных выполняет резервное копирование каждые 6 часов, а те базы данных, которые у вас есть, хранят файл размером 10 МБ на запись. Этот сценарий не то, что вы хотите.
PataoEngineer Tao
источник