Зберігання файлів в MySQL і їх швидка роздача
Але у такого класичного походу безліч недоліків:- файли залишаються при видаленні відповідного запису БД
- проблеми при одночасній спробі оновлення файлу
- порушення синхронізації між БД і файлової системою при відкат транзакції
- при резервного копіювання та відновлення інформації в БД може виникнути рассинхронизация з файлової системою
- файли не підкоряються обмеженням доступу, накладеним за допомогою БД
- Перед видаленням запису робити SELECT з тим же умовою і отримувати імена файлів, які треба видалити. Проблема в тому, що якщо файлів, що видаляються багато, ця операція може зайняти деякий час і по хорошому на цей час треба блокувати таблицю на читання і запис, а в багатьох випадках це неприпустимо.
- Перед видаленням встановлювати у видаляються записів мітку «підлягає видаленню», отримати всі записи з цією міткою і видалити файли, пов'язані з цими записами, і нарешті видалити всі записи з цією міткою. Запити, що працюють з цією таблицею слід доопрацювати, щоб вони не вибирали записи з встановленим прапором. Недоліки - необхідність редагування безлічі запитів, до того ж у нас в проекті записи на видалення відбираються досить складним SELECT, які не можна переробити в один UPDATE.
- Перші два способи намагаються вирішити проблему «втрачених» файлів при видаленні записів в БД, яка виникає при «класичному» способі зберігання файлів, однак вони не вирішують інших проблем такого підходу, тому ми спробували придумати рішення, які використовують позитивні моменти зберігання файлів прямо в БД і позбутися від недоліків, властивих цим підходом.
- Використовувати тригери. На жаль, MySQL не має в своїй мові підтримки команд роботи з файлами, такі команди довелося б реалізовувати самостійно, длубаючись в исходниках MySQL. З мінусів - файли повинні зберігатися на тому ж хості, що і БД, необхідність доопрацювання MySQL, таких готових рішень ми не знайшли.
- Зберігати файли в БД, але віддавати їх безпосередньо вебсервер, без участі PHP. Реалізувати це можна, написавши модуль до веб-сервера (nginx наприклад) який дозволяв би віддавати файли безпосередньо з MySQL або застосувавши драйвер файлової системи MySQLfs. Такий підхід вирішує всі перераховані вище проблеми, але його недолік - додаткові накладні витрати на зберігання файлів в MySQL.
- Спеціалізований Storage Engine для MySQL, який зберігає записи як файли.
Зупинимося детальніше а останньому пункті. Адже що собою являє файлова система - це спеціалізована БД, яка по ключу «ім'я файлу» дозволяє отримати запис - його вміст. Тобто можна реалізувати свій механізм зберігання даних для MySQL, в якому кожен запис буде мати три поля:
CREATE TABLE `data_storage`.`files` (
`Id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`Path` VARCHAR (255),
`Data` BLOB
) ENGINE = FILES
Вставляти дані в таку таблицю можна тільки в поле `data`, при цьому вони просто зберігаються в файл, унікальне ім'я йому при цьому генерується автоматично (використовуючи в якості префікса поле` id`) - наприклад 764533, а в поле `path` автоматично підставляється правильний шлях, по якому MySQL поклав наші дані - наприклад '/mnt/storage/mysqldata/76/45/33/764533_myfile.jpg'. Таким чином до даних, збереженим в такій таблиці можна звертатися як до простих файлів, і при цьому MySQL буде підтримувати цілісність даних. Таким чином цей спосіб зберігання файлів позбавлений практично всіх недоліків класичного підходу (крім обмеження доступу, а й його можна зробити використовуючи простий скрипт і заголовок X-Accel-Redirect nginx) і в той же час ніяк не применшує продуктивність при віддачі файлів клієнтам.
Проблема за малим - не вдалося знайти готової реалізації такого движка зберігання даних для MySQL, хоча ідея загальному то проста. Можливо хтось з хабролюдей підкаже посилання на готову реалізацію такого storage engine, ідея адже плаває на поверхні, і її точно хтось уже міг реалізувати.