Структура базы:
База данных была спроектирована задолго до меня и эксплуатируется уже несколько лет.
Нас интересует только одна таблица – adcdata, в которой и хранятся отсчеты АЦП. В поле adcdata хранится весь сигнал целиком.
Задача была записывать в это поле сигнал. Данные с АЦП поступаю порциями. При частоте 400кГц, поступает 768кБ/с. Эти данные нужно дописывать в гонец поля adcdata.
Конечно, хотелось писать в базу "налету", без всяких буферов на клиентской стороне. Но задача дозаписи данных в поле (запись в конец поля) для реляционных СУБД оказалась нетривиальной. Информации по таким решениям в интернете я не нашел. Вот несколько алгоритмов, придуманных мной.
Алгоритм №0
Идея: делаем SELECT уже записанных данных, на клиентской стороне приклеиваем к ним новую порцию данных и UPDATE-им все это в базу. Этот вариант пришел в голову первым и является совсем тупым решением. Я его даже не рассматривал.
Чтобы сделать UML диаграммы компактнее, я выбросил второстепенные параметры из SQL запросов.
Сперва, этот вариант показался мне лучшим решением, которое только возможно придумать. Сигналы с АЦП записываются в базу данных налету (порциями), за конкатенацию отвечает СУБД, следовательно, не придется туда-сюда их гонять. Но не всебыло так хорошо...
VALUES (@exp_id, @channel, @gain, @adcdata)
UPDATE adcdata SET adcdata = CONCAT(adcdata, @adcdata)
WHERE exp_id = @exp_id AND channel = @channelSyhi-подсветка кода
Как оказалось, при выполнении конкатенации сервер сначала извлекает все содержимое поля adcdata в оперативную память, затем производит склейку и только потом записывает результат в поле.
Алгоритм №2
Второй алгоритм, придуманный мной, потребовал создания в базе данных дополнительной, временной таблицы. Идея заключалась в том, чтобы каждую новую порцию данных вставлять в очереднцю строку иаблицы. А по окончании процесса сбора данных, обработать содержимое этой таблицы хранимой процедурой и записать сигналы в исходную таблицу adcdata. Таким образом сохранялась совместимость с существующей структурой базы данных.

Алгоритм №3
Как-то перечитывая документацию к MySQL я наткнулся на ключевое слово DELAYED. Его употребление вместе с INSERT дает возможность не дожидаться окончания выполнения запроса. Жаль, что для UPDATE его нельзя применить :) Я модифицировал алгоритм №2 так:
Тест алгоритмов
Чтобы положить какие-то цифри в фундамент моих догадок относительно производительности этих алгоритмов, я написал небольшое тестовое приложение на C#. "Причем тут C#?", - спросите Вы. Все просто. Во-первых, мне были нужны относительные результаты. Во-вторых, на C# это было сделать просто. В-третьих, я даже не заморачивался насчет аппаратной конфигурации, так как мне нужены был качественные различия.
Вот такие результаты я получил:
Алгоритм 1. Как я уже говорил - чем больше данных записано в поле adcdata в конкретный момент времени, тем больше времени сервер потратит на конкатенацию.Алгоритм 2. Показал стабильное время вставки данных с небольшими случайными всплесками.
Алгоритм 3. Как и ожидалось, это самый стабильный алгоритм.
К слову, об алгоритме 2 и 3. Тут нужно использовать хранимые процедуры, а это только MySQL 5.0 и выше.
P.S.: А как я все-таки реализовал запись сигналов в базу данных читайте в следующем посте про LabVIEW Database Connectivity Toolset.


Комментариев нет:
Отправить комментарий