Стартовая страница › Форумы › Новые идеи › Scada Server. Текст (предложение)
- В этой теме 40 ответов, 3 участника, последнее обновление 4 часа, 9 минут назад сделано
manjey73.
-
АвторЗаписи
-
03.10.2026 в 12:27 #45250
manjey73УчастникА теперь реалистичный случай: 30 000 каналов, из них 100 текстовых, остальные аналоговые.
более реалистичный случай — ты просто не сохраняешь в БД эти 100 текстовых каналов в рамках scada. Их нет в записях БД, исключены.
и пишешь только в свою БД ПО ИЗМЕНЕНИЮ средствами ArcBasicText.dll как хочешь.
Даже если эти 100 каналов фактически будут массивами
03.10.2026 в 12:27 #45251
JurasskParkУчастникТак у тебя получится [Timestamp: 8][Quality: 2][Val: 8][ValId: 4] = 22 байта — разве нет?
Нет. Val и ValueId — это взаимоисключающие поля. В записи присутствует либо одно, либо другое, в зависимости от типа канала.
Канал числовой (Type = Double):
[Timestamp: 8][Quality: 2][Val: 8] = 18 байт
↑ только ValКанал текстовый (Type = TextRef):
[Timestamp: 8][Quality: 2][ValueId: 4] = 14 байт
↑ только ValueIdКанал текстовый plain (Type = TextPlain):
[Timestamp: 8][Quality: 2][len: 2][utf8: N] = 12 + N байт
↑ строка целиком22 байта не получается ни в одном случае. Числовой канал пишет 18 байт — ровно столько же, сколько и сейчас, без изменений.
Как сервер узнает, что ты добавил id для текста или не добавил?
Из дескриптора канала. Тип канала — это не свойство сэмпла, а свойство канала. Он хранится в конфигурации (в _meta.dat папки архива, рядом с дескрипторами каналов), и сервер уже сейчас его читает, чтобы понять, как интерпретировать данные.
Смотри, как это работает при чтении архива:
1. Сервер открывает папку Min/2026-10-03/ 2. Читает _meta.dat → получает список каналов и их типы: Cnl 50 Type = Double → запись 18 байт Cnl 51 Type = Double → запись 18 байт Cnl 52 Type = TextRef → запись 14 байт Cnl 53 Type = TextPlain → запись 12 + N байт ... 3. Открывает data.dat, читает блоки данных, зная для каждого канала его размер записи. 4. Для Type = TextRef дополнительно читает dict.dat и подставляет текст по ValueId.Никакого флага «в этом сэмпле есть текст, а в этом нет» не нужно. Тип известен заранее — на уровне канала, один раз, а не на каждом сэмпле.
Кто определяет, что из себя представляет канал — числовой он или текстовый?
Инженер при конфигурировании системы. Ровно так же, как сейчас определяется, что канал 50 — это Double, а канал 51 — это Integer. В RapidScada 6 тип канала уже существует в конфигурации:
— Double
— Integer
— Boolean
— String (с указанием длины)
Я предлагаю добавить к этому списку ещё два:
TextRef — текст через словарь (для типичных SCADA-строк: RUN, STOP, ALARM, названия рецептов)
TextPlain — текст целиком (для строк с высокой кардинальностью или произвольных)
Или, ещё проще: оставить существующий String, но дать ему два режима хранения — через словарь и plain. Выбор режима — либо вручную инженером, либо автоматически по кардинальности (адаптивно, как я писал ранее).Или ты говоришь о том, чтобы перелопатить весь код Сервера?
Компонент — Что меняется
Формат .dat — Новый тип канала в дескрипторе + новый файл dict.dat в папке архива
Чтение архива (ScadaServerEngine) — Ветвление по типу канала: Double → читаем 8 байт, TextRef → читаем 4 байта и идём в словарь
Запись архива — Аналогично: пишем либо Val, либо ValueId в зависимости от типа
DTO CnlDataPoint — Опциональное поле ValueId для передачи текста клиенту (не на диск, а в памяти)
API сервера — Метод чтения текстового значения по ValueId (или возврат строки сразу из DTO)Драйверы, Коммуникатор, ScadaComm, модули сбора данных — не трогаются. Они как присылали строки, так и будут присылать. Меняется только слой хранения и API чтения.
Аналог: если в PostgreSQL добавить новый тип колонки, это не значит, что весь PostgreSQL переписывается. Меняется парсер, планировщик и слой хранения — но не драйверы и не клиентские библиотеки.
Числовые каналы не платят ничего. Текстовые — платят меньше, чем сейчас (14 байт против 18 при plain-хранении, плюс колоссальная экономия за счёт того, что сам текст пишется один раз, а не на каждый сэмпл).
Так что «перелопатить весь код» — нет. Перелопатить слой хранения и API чтения — да.
03.10.2026 в 12:37 #45252
manjey73Участник1. Тип строка возможен в устройствах, и читает это Коммуникатор и передаёт Серверу он же.
2. Это уже другая БД для строк.В результате надо переписать ещё и Коммуникатор, чтобы он не делил строки, а перевал их полностью в Сервер.
Переписать ещё Сервер, чтобы получая строку он ее дожил в другую БД, с тем механизмом, что ты предлагаешь.И что ещё переписать придется? Для отображения в том числе?
03.10.2026 в 12:42 #45253
manjey73УчастникКоммуникатор не присылает Серверу полную строку к сожалению 🙁
Если бы присылал, уже давно бы что-нибудь придумал 🙂03.10.2026 в 12:54 #45254
manjey73Участникз.ы. не экономим на 4-х байтах, а просто их используем, кроме id можно указывать тип Ascii/Unicode (хотя это и так есть) и длину строки — не думаю, что там ‘Войну и Мир’ в юникоде запихнут.
тут важно, чтобы Коммуникатор и Сервер просто работали с полными строками, а не кромсали их на 8 байт. Без этого, все это фигня на постном масле. Имхо.
-
Ответ изменён 2 дня, 11 часов назад пользователем
manjey73.
03.10.2026 в 12:58 #45256
manjey73УчастникИ в устройствах Modbus тоже есть строки, поверх регистров, и его тоже надо научить понимать строки, предлагал вариант с созданием структуры при настройках шаблона.
03.10.2026 в 14:10 #45257
JurasskParkУчастникКак работает сейчас коммуникатор и как он отдает данные — это отдельная задача, КОТОРАЯ НИКОГО ОТНОШЕНИЯ к моему предложению не имеет отношения. Слона надо есть по кусочкам, а не целиком.
Даже если Коммуникатор сейчас передаёт строку корректно (через массив каналов, как в v6) — на стороне архива она всё равно:
— Упаковывается в double (по 8 байт на элемент массива),
— Пишется на каждый сэмпл,
— Дублируется между сэмплами, между каналами, между днями.
Именно эту проблему решает словарь. Независимо от того, как строка дошла до Сервера.Словарь живёт между Сервером и Архивом. Он не знает и не хочет знать, как строка дошла — целиком или кусками. Если строка дошла целиком — отлично, словарь её сохранит один раз. Если дошла кусками (массивом каналов) — Сервер склеил её в одну строку до записи в архив, и дальше словарь работает как обычно.
То есть логика такая:
1. Сервер получил от Коммуникатора сэмпл канала (число или массив для строки). 2. Если канал текстовый — Сервер собирает полную строку (сейчас он это уже умеет делать для отдачи в UI). 3. Перед записью в архив — Сервер проверяет строку в словаре дня: - есть → берёт существующий ValueId - нет → добавляет и получает новый ValueId 4. В data.dat пишет только ValueId. В dict.dat — текст.Никакой доработки Коммуникатора на этом шаге не требуется. Он как передавал данные, так и передаёт.
Если мы хотим, чтобы длинные строки ходили от устройства до Сервера одним куском, то да, нужно смотреть в сторону Коммуникатора и драйверов. Но это отдельная задача, и она не блокирует задачу хранения. Можно сделать сначала словарь (хранение), а потом уже заниматься транспортом (Коммуникатор и драйверы).
Для самого словаря трогать Коммуникатор не нужно. Он нужен только для того, чтобы строки ходили целиком, а это уже вопрос, как их отдают устройства и драйверы.
не экономим на 4 байтах, а используем их
Сейчас:
— Строка упаковывается в double — 8 байт.
— Если строка длиннее 8 байт — используется массив каналов, и каждые 8 байт пишутся в архив на каждый сэмпл.
— История изменений длинной строки превращается в поток дубликатов.Словарь решает вторую и третью проблему (дубликаты и историю), но не решает первую (транспорт). И это нормально: разные задачи — разные решения.
Ты прав насчёт Коммуникатора — это реальная проблема. Но она отдельная от хранения. Словарь ValueId можно внедрить до решения проблемы транспорта, и он даст эффект уже на текущих данных.
Ты пытаешься решить все проблемы сразу: транспорт строк от Modbus-регистров, обрезание в Коммуникаторе, хранение в архиве, отображение в клиентах. И требуешь, чтобы любое предложение закрывало всё это целиком, иначе — «фигня».
03.10.2026 в 14:27 #45258
manjey73Участникя вот одного не пойму, куда ты stat потерял ?
public CnlDataPoint(int cnlNum, DateTime timestamp, double val, int stat, int valueId) { CnlNum = cnlNum; Timestamp = timestamp; Val = val; Stat = stat; ValueId = valueId; }stat же тоже лежит с каждым каналом отдельно — 4 байта int — у каждого канала свой статус же.
timestamp 8 байт, значение 8 байт, статус 4 байта. — и 4 байта еще собственно номер канала — как бы 24 байта на канал а не 14.
то ест переделка только Сервера, чтобы он склеил полученные куски строк и сохранил рядом, не создавая массив каналов для строк. Ну и чтобы Коммуникатор вдруг не упал, так как канала 1,2,3 не будет, а будет только 0-вой у «массива»
03.10.2026 в 14:30 #45259
manjey73Участниккто-то что-то потерял? Когда смотришь утилитой БД по каналу, ты видишь только время, значение и статус.
Но в базе то оно все в куче.На Н-ное время
Канал1, данные, статус
Канал2, данные, статусили даже так
Канал1, время, данные, статус
Канал2, время, данные, статус03.10.2026 в 14:33 #45260
manjey73Участникв папке Min на каждый час свой файл dat поминутно, то есть в файле по 60-т записей на все каналы.
-
Ответ изменён 2 дня, 10 часов назад пользователем
manjey73.
05.10.2026 в 20:36 #45279 -
Ответ изменён 2 дня, 11 часов назад пользователем
-
АвторЗаписи
- Для ответа в этой теме необходимо авторизоваться.