Связаться
[email protected]+375 29 217-89-90220117, г. Минск, ул. Газеты Звязда, 16, пом. 53, офис 9В
Девять машинных прогонов 27 сентября 2026 на одной и той же базе, одних и тех же данных и одном веб-сервере. Ниже — условия стенда, набор запросов, все полученные цифры и отдельным разделом то, чего в этих цифрах нет. Без условий замера любое число на этой странице ничего не стоит, поэтому они идут первыми.
Данные не синтетические: генератор копирует существующие объекты демобазы и подменяет у них ключевые поля — отсюда реалистичные типы и ссылки. Значения берутся из полусотни образцов, поэтому кардинальность реквизитов ниже, чем в живой базе, и СУБД работать легче.
Одиночные мелкие запросы у нас немного медленнее штатного интерфейса: $top=1 — 28 мс против 14 мс.
Записи регистра бухгалтерии на миллион строк страницами по умолчанию отстают: 199 с против 124 с.
Всё мерено на файловой базе с Apache на той же машине. Клиент-серверная не замерена.
Одновременная работа многих клиентов не замерена.
Прогоны шли на машине, занятой и другой работой: разброс повторов ±10–20 %.
Первый $apply по миллиону записей на холодном кэше файловой базы занял 207 с, дальше — около 1,1 с.
Страница с продолжением по составному ключу на таблице в миллион строк дорожает до 4,4 с: похоже, в файловой базе условие продолжения не использует индекс.
Три сущности на одной базе: OData4 с выдачей на языке 1С, OData4 с компонентой на Rust и штатный standard.odata. Адреса — /hs/odata/v4 и /odata/standard.odata одной и той же публикации, вход Basic под одним пользователем.
секунды, меньше — лучше
Документы с табличными частями — единственный набор, где отрыв заметный: штатный интерфейс отдаёт их одним ответом на 3,8 ГБ и тратит на это больше четырёх минут. На записях регистра бухгалтерии мы, наоборот, отстаём.
Документы с табличными частями
100 тыс. документов, ответ 3,5 ГБ
Записи регистра накопления
1,09 млн записей
Записи регистра бухгалтерии
1,12 млн записей — здесь мы медленнее
Справочник целиком
100 тыс. элементов, ответ 154 МБ
гигабайты, меньше — лучше
Те же данные в более компактном JSON: на наборах записей регистров ответ примерно вдвое меньше. Это и трафик, и время разбора на стороне клиента.
Записи регистра накопления
1,09 млн записей
Записи регистра бухгалтерии
1,12 млн записей
Документы с табличными частями
100 тыс. документов
миллисекунды, меньше — лучше
Постоянная стоимость запроса у нас выше: своё маршрутизирование и своя модель стоят около десятка миллисекунд. На $metadata это окупается кэшем между сеансами — 28 мс против 402.
$metadata, тёплый сеанс
описание модели, 5,4 МБ против 8,5 МБ
Balance() регистра бухгалтерии
ответ 1,9 МБ
$filter по номеру, 100 документов
ответ 3,5 МБ
Turnovers() регистра накопления
ответ 47 КБ
Справочник, $top=1
одна запись
секунды, меньше — лучше
Здесь штатный интерфейс быстрее: он отдаёт всё одним ответом, а мы платим за страницы с продолжением. На таких объёмах разница в пару секунд, и ощутимой она становится только на гигабайтах.
Справочник целиком
154 МБ
Справочник, три поля
13,9 МБ
Документы, три поля
10,5 МБ
во сколько раз быстрее, чем выдача на языке 1С
Компонента необязательная: если её нет, сервис работает на языке 1С и отвечает теми же ответами, только медленнее. Там, где время уходит не на сериализацию, а на запрос страницы, выигрыш меньше — последний ряд.
Страница документов с табличными частями
9 088 → 1 450 мс
Документы целиком, 3,5 ГБ
992 → 161 с
Документы, три поля
10,5 → 2,5 с
Справочник целиком, 154 МБ
47,9 → 11,7 с
Записи регистра накопления, 1,5 ГБ
853 → 471 с
миллисекунды, страница из 1000 документов
Запрос к базе и выгрузка результата занимают единицы миллисекунд, сериализация JSON — 93–97 % всего времени. Из этого разложения и выросло решение вынести выдачу в компоненту.
Сериализация JSON
Сборка строк табличных частей
Формирование ответа
Выгрузить()
Запрос к базе
секунды, 1,09 млн записей регистра накопления
Один и тот же набор, разные настройки выдачи: разница между худшим и лучшим вариантом — почти вчетверо. Страницами по умолчанию OData4 отстаёт от штатного интерфейса, страницами по 5000 — догоняет, одним ответом — обходит.
Страницами по 1000
1 089 запросов с продолжением
Страницами по 5000
218 запросов
Одним ответом
без @odata.nextLink
standard.odata, одним ответом
ответ 3,3 ГБ вместо 1,5 ГБ
Ниже — полные прогоны, из которых собраны графики выше: четыре объёма базы, разложение времени внутри 1С, выбор способа передачи данных в компоненту и запись.
Медиана по трём повторам, мс. Выдача OData4 — на языке 1С.
| Замер | OData4 | standard.odata |
|---|---|---|
| Страница документов | 1 004 | 153 |
| Документы целиком | 1 004 | 156 |
| Документы, три поля | 24 | 12 |
| Документы, $filter | 12 | 13 |
| Строки табличной части целиком | 251 | 63 |
| Строки табличной части, $expand | 604 | 198 |
| Справочник, $top=1 | 26 | 13 |
| Справочник целиком | 43 | 16 |
| Справочник, три поля | 9 | 11 |
| Записи регистра накопления | 1 153 | 229 |
| Записи регистра бухгалтерии | 6 804 | 1 304 |
| Turnovers() | 26 | 18 |
| Balance() регистра бухгалтерии | 762 | 182 |
| $apply | 10 | — |
| $batch, 50 операций | 829 | — |
| $metadata XML, тёплый | 25 | 396 |
| $metadata JSON, тёплый | 24 | — |
Медиана, мс. Выдача OData4 — на языке 1С: именно эти цифры и стали поводом написать компоненту.
| Замер | OData4 | standard.odata | Объём ответа |
|---|---|---|---|
| Страница документов, 44 тыс. строк | 9 020 | 1 540 | 32,3 МБ |
| Документы, три поля, все страницы | 126 | 21 | 127 КБ |
| Документы, $filter, 100 шт. | 1 027 | 150 | 3,5 МБ |
| Строки табличной части, 12 страниц | 3 131 | 782 | 10,2 МБ |
| Справочник, 2 страницы | 512 | 121 | 1,6 МБ |
| Записи регистра накопления, 109 страниц | 52 740 | 9 341 | 152 МБ |
| Записи регистра бухгалтерии, 135 страниц | 60 942 | 10 506 | 138 МБ |
| Turnovers() | 186 | 18 | 46 КБ |
| Balance() регистра бухгалтерии | 794 | 199 | 1,9 МБ |
| $apply groupby/aggregate | 213 | — | 338 Б |
| POST + PATCH + DELETE | 121 | — | — |
| $batch, 50 операций | 1 103 | — | 95 КБ |
| $metadata XML, первый / тёплый | 2 745 / 26 | 402 / 411 | 5,4 МБ |
| $metadata JSON, первый / тёплый | 2 582 / 23 | — | 4,7 МБ |
Медиана, мс. «Страниц» — сколько ответов отдал OData4 при полном обходе.
| Замер | Без компоненты | С компонентой | standard.odata | Страниц |
|---|---|---|---|---|
| Страница документов | 8 948 | 1 493 | 14 252 — всё одним ответом | 1 |
| Документы целиком | 99 864 | 16 880 | 14 335 | 11 |
| Документы, три поля | 1 025 | 204 | 98 | 11 |
| Документы, $filter | 1 027 | 222 | 149 | 1 |
| Строки табличной части целиком | 38 904 | 15 950 | 5 359 | 101 |
| Строки табличной части, $expand | 1 818 | 1 328 | 23 388 — всё | 1 |
| Справочник, $top=1 | 25 | 27 | 13 | 1 |
| Справочник целиком | 4 724 | 1 119 | 1 060 | 11 |
| Справочник, три поля | 616 | 218 | 102 | 11 |
| Записи регистра накопления | 107 194 | 24 693 | 18 474 | 198 |
| Записи регистра бухгалтерии | 122 709 | 34 801 | 18 181 | 225 |
| Turnovers() | 28 | 16 | 20 | 1 |
| Balance() регистра бухгалтерии | 796 | 199 | 194 | 2 |
| $apply | 115 | 109 | — | 1 |
| POST + PATCH + DELETE | 120 | 126 | — | 1 |
| $batch, 50 операций | 1 098 | 1 168 | — | 1 |
| $metadata XML, тёплый | 26 | 25 | 406 | 1 |
Лёгкие замеры — медиана после прогрева, тяжёлые обходы — один проход. standard.odata показан там, где его ответ разумного размера.
| Замер | Без компоненты | С компонентой | standard.odata | Страниц | Объём |
|---|---|---|---|---|---|
| Страница документов | 9 088 | 1 450 | — | 1 | 32,3 МБ |
| Документы целиком | 992 314 | 160 791 | — | 101 | 3,5 ГБ |
| Документы, три поля | 10 471 | 2 480 | 932 | 101 | 10,5 МБ |
| Документы, $filter | 1 038 | 221 | 182 | 1 | 3,5 МБ |
| Строки табличной части, $expand | 16 135 | 15 487 | — | 1 | 2,3 МБ |
| Справочник, $top=1 | 28 | 28 | 14 | 1 | — |
| Справочник целиком | 47 856 | 11 663 | 10 689 | 101 | 153,5 МБ |
| Справочник, три поля | 6 308 | 2 923 | 972 | 101 | 13,9 МБ |
| Записи регистра накопления | 853 406 | 471 346 | — | 1 089 | 1,5 ГБ |
| Записи регистра бухгалтерии | 963 679 | 637 858 | — | 1 121 | 1,1 ГБ |
| Turnovers() | 29 | 18 | 19 | 1 | — |
| $apply groupby/aggregate | 1 059 | 1 109 | — | 1 | — |
| Balance() регистра бухгалтерии | 785 | 230 | 196 | 2 | 1,9 МБ |
| POST + PATCH + DELETE | 134 | 129 | — | 1 | — |
| $batch, 50 операций | 1 059 | 1 196 | — | 1 | — |
| $metadata XML / JSON, тёплый | 28 / 25 | 28 / 25 | 402 | 1 | 5,4 МБ |
Ступень 100 тыс., один проход, секунды. Выдача OData4 — компонентой.
| Набор | Страницами по 1000 | По 5000 | Одним ответом | standard.odata |
|---|---|---|---|---|
| Документы с табличными частями, 3,5 ГБ | 161–199 | — | 229 | 257–263 |
| Справочник, 154 МБ | 12–20 | 12 | 11,2 | 10,7 |
| Записи регистра накопления, 1,5 ГБ | 493 | 145 | 134 | 147 |
| Записи регистра бухгалтерии, 1,1 ГБ | 636 | — | 199 | 124 |
| Показатель | OData4 | standard.odata |
|---|---|---|
| Записи регистра накопления, 1,09 млн | 1,5 ГБ | 3,3 ГБ |
| Записи регистра бухгалтерии, 1,12 млн | 1,1 ГБ | 2,2 ГБ |
| Документы с табличными частями, 100 тыс. | 3,5 ГБ | 3,8 ГБ |
| Строки табличной части с $expand, 1 млн | страница 2,3 МБ | 3,7 ГБ одним куском |
| $metadata XML | 5,4 МБ | 8,5 МБ |
| $metadata JSON | 4,7 МБ | — |
| Пик памяти Apache при ответе на 1,5–3,5 ГБ | 1,4–1,7 ГБ | — |
Разложение вызова на странице в 1000 записей, медиана, мс. Выдача — на языке 1С: видно, за что платит сервис без компоненты.
| Набор | Весь вызов | Запрос | Выгрузить | Строки ТЧ | Сериализация | Ответ |
|---|---|---|---|---|---|---|
| Документы, 44 тыс. строк ТЧ | 8 254 | 3 | 11 | 427–1 002 | 7 816 | 81 |
| Записи регистра накопления | 389 | 5 | 7 | — | 376 | 3 |
| Записи регистра бухгалтерии | 340 | 5 | 7 | — | 327 | 3 |
| Справочник, 679 строк ТЧ | 395 | 4 | 15 | 20 | 357 | 3 |
| Документы, три поля | 86 | 1 | 3 | — | 81 | 0 |
Первый запрос нового сеанса на составе из 1 371 объекта и 2 203 наборов. «Память» — сколько держит сеанс.
| Первый запрос нового сеанса | Полная модель | Ленивая модель |
|---|---|---|
| Один набор Catalog_Валюты | 1,6 с, 49,6 млн знаков | 0,17 с, 1,28 млн знаков |
| Набор с $expand | 49,6 млн знаков | 1,63 млн знаков |
| $metadata XML | 2,2 с, 54,4 млн знаков | 2,4 с, 6,0 млн знаков |
| $metadata, холодный, с кэшем между сеансами | ~2,7 с | ~0,55 с |
| $metadata, тёплый сеанс | — | 26 мс |
Миллисекунды. Запись почти не зависит от объёма базы.
| Операция | 1 тыс. | 10 тыс. без комп. | 10 тыс. с комп. | 100 тыс. без комп. | 100 тыс. с комп. |
|---|---|---|---|---|---|
| POST + PATCH + DELETE элемента справочника | 121 | 120 | 126 | 134 | 129 |
| $batch, 50 операций GET | 1 103 | 1 098 | 1 168 | 1 059 | 1 196 |
100 тыс. строк по 24 колонки. Выбор способа передачи и был главным решением: неудачный способ съедал весь выигрыш компоненты.
| Способ | Упаковка в 1С | Передача | Итого |
|---|---|---|---|
| По одному значению | 4 931 | ~8 300 | 13 207 |
| Строка с разделителями | 7 747 | 145 | 7 892 |
| JSON, массив массивов | — | — | 6 465 |
| Внутренний формат таблицы значений, 81 млн знаков | — | — | 1 316 |
Миллисекунды. Разбор занимает около 1 % времени $batch — ускорять там нечего.
| Операций | JSON batch | multipart/mixed | Тела записи |
|---|---|---|---|
| 50 | 11 | 4 | 4 |
| 1000 | 75 | 77 | 13 |
Стенд собирается из эталонной демобазы, генератор досыпает данные ступенями, прогон пишет итог в файл. Эталон и клоны при этом не меняются.
Прогон
devcli bench create --name odata4bench --ref D:\1c-bases\odata4demo
devcli bench deploy --name odata4bench
devcli bench generate --step 100000 --budget 5m
devcli bench run --repeat 5 # лёгкие замеры
devcli bench run --repeat 0 --only "all|records" # тяжёлые обходы
devcli bench breakdown --path Document_НачислениеЗарплаты --repeat 3