Работа с BLOBами

d

Практика работы с BLOB: не все бинарные данные одинаково полезны

BLOB (Binary Large Object) — механизм хранения бинарных данных в SQL-базах. В Delphi работа с ними идёт через TBlobField и методы LoadFromStream/SaveToStream. Ошибка №1 — думать, что BLOB подходит для любых файлов. На практике выбор между BLOB и файловой системой — вопрос производительности и архитектуры.

Разберём три реальных сценария, для которых я подбирал решение под конкретную задачу в 2023-2025 годах.

Сценарий 1: Много мелких файлов (до 200 КБ) — XPS-документы

Заказчик хранил 150 000 XPS-файлов в папке на NAS. Проблема: резервное копирование занимало 14 часов. Переход на SQLite с BLOB (без сжатия) уменьшил время бэкапа до 2 часов.

Сценарий 2: Изображения 2-5 МБ — PostgreSQL + TStream

Интернет-магазин: 40 000 фото товаров. Поле BYTEA (PostgreSQL). Ошибка: все фото хранили одной таблицей. Пришлось сделать отдельную таблицу product_images и подключать LEFT JOIN — иначе сканирование строк тормозило вывод каталога.

  1. Шаг выбора: размер файла >1 МБ — файловая система лучше для частого чтения. Но клиент настоял на единой БД.
  2. Оптимизация: сжатие WebP (снизили размеры с 4.5 МБ до 1.2 МБ) перед записью в BLOB.
  3. Код загрузки на Delphi: TMemoryStream -> TBlobField(FieldByName('image')).LoadFromStream.
  4. Цифра: время выборки 100 записей с BLOB — 1.2 сек (без индексации). С индексом по ID — 0.3 сек.

Сценарий 3: Видеофрагменты (50-100 МБ) — BLOB убивает производительность

В проекте системы видеонаблюдения (Delphi 12, FireDAC) инженеры положили 30-секундные ролики в BLOB MS SQL Server. Результат: размер БД 200 ГБ, страницы памяти переполнены. Пришлось мигрировать на файловую систему, а в БД хранить только путь.

Типичные ошибки покупателей (разработчиков) при выборе стратегии

  1. Путают OLTP и архивирование. BLOB для транзакционной нагрузки — частая проблема. На приёме: “а почему база тормозит?” — потому что запрос SELECT * с BLOB полем выгружает мегабайты при выборе пары строк.
  2. Игнорируют резервное копирование. Маленькое изменение в файле — и полный дамп, если БД одна. Всегда храните BLOB отдельной файловой группой или таблицей.
  3. Забывают про потоковую запись. Код вида FieldByName('data').AsString := FileToBase64 — кошмар. Используйте LoadFromStream.
  4. Не проверяют встроенные средства СУБД — например, FILESTREAM в SQL Server или lo в PostgreSQL. Они работают быстрее обычного BLOB.

Пошаговый шаблон для принятия решения

В Delphi для типовых действий с BLOB используйте TFDQuery или TADOQuery. Пример записи:

var MemStream: TMemoryStream;
MemStream := TMemoryStream.Create;
try
MemStream.LoadFromFile('foto.jpg');
with FDQuery1 do begin
SQL.Text := 'UPDATE products SET image = :blb WHERE id = 42';
Params.ParamByName('blb').LoadFromStream(MemStream, ftBlob);
ExecSQL;
end;
finally MemStream.Free; end;

Избегайте ParamByName('blb').SetBlobData — в FireDAC он допускает утечку памяти на версиях до 2024.

Добавлено: 27.04.2026