Эффективный способ сохранения изображений в БД из PHP GD image object

#php #gd

#php #gd

Вопрос:

Мне нужно сгенерировать и сохранить в базе данных множество небольших (1-10 КБ) изображений в формате PNG (> 10 миллионов). Единственное, что меня волнует, это пропускная способность изображений в секунду. На данный момент я знаю два способа сохранения объекта GD image в базе данных:

Используйте выходной буфер:

 ob_start();
imagepng($image);
$imageData = ob_get_contents();
ob_end_clean();
  

Используйте временный файл (tmpfs / ramfs):

 $tmpFilePath = '/dev/shm/file_000.png';
imagepng($image, $tmpFilePath);
$imageData = file_get_contents($thumbnail);
  

Обновить. Существует третий способ: использовать поток памяти PHP:

 // PHP streams are NOT supported
$tmpFilePath = 'php://memory';
imagepng($image, $tmpFilePath);
$imageData = file_get_contents($tmpFilePath);
  

Мой вопрос в том, существуют ли какие-либо другие способы записи изображений в БД? Любые плюсы / минусы каждого метода.
Может быть, стоит написать пользовательский поток, который записывает данные в БД напрямую?

Примечание: Сохранение изображений в файловой системе не является вариантом.

Результаты тестирования:

Генерация и сохранение 10 тысяч изображений PNG

Комментарии:

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

Ответ №1:

Вы могли бы попробовать разрешить imagepng() запись в поток памяти вместо файла.

 $tmpFilePath = 'php://memory/file_000.png';

imagepng($image, $tmpFilePath);
$imageData = file_get_contents($tmpFilePath);
  

Хотя я не уверен, что imagepng() функция может обрабатывать потоки ввода-вывода, если это так, это может быть хорошей альтернативой.

Ответ №2:

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

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

Комментарии:

1. Я подготовлю тест чуть позже. Сейчас я сосредотачиваюсь на возможных вариантах.

Ответ №3:

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

Комментарии:

1. Я не уверен, использую ли я send_long_data (это стоит другого вопроса). Что вы имеете в виду, говоря «буфер памяти»?

2. Я имел в виду $imageData = ob_get_contents(); строку, когда вы загружаете изображение в память.

Ответ №4:

Оба варианта вряд ли повлияют на ваше общее время выполнения, поскольку в наши дни openreadclose’in кэшированного файла в Linux занимает около 20 микросекунд. Генерация и сжатие изображений потребуют много времени (сначала вы должны оптимизировать ту часть, которая занимает больше всего времени). Если вы действительно хотите сэкономить 1% от общего времени, используйте функции ob_().

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

Комментарии:

1. В моем случае большие двоичные объекты небольшие, поэтому есть надежда достичь действительно хорошей производительности 🙂

2. Вы ошибаетесь насчет time-eater. 10k изображений генерируются за 16 секунд (на двух ядрах Xenon 5650). Генерация и запись всех изображений на жесткий диск занимает 187 секунд, хотя причиной может быть метод imagepng.

3. Сохранение 10000 файлов займет меньше секунды (если вы, конечно, не используете NTFS); однако PNG включает сжатие, которое требует времени. Можете ли вы предоставить несколько примеров изображений?

4. Как вы можете видеть из результатов, запись в память 10k в 3 раза быстрее. Общая экономия времени составляет более 1%.