Пагинация в 1С

09.01.23

Интеграция - WEB-интеграция

Те, кому приходилось делать REST API на базе HTTP-сервисов 1С, могли в какой-то момент столкнуться с необходимостью разработки методов, которые позволяли бы возвращать данные с пагинацией, т.е. последовательными порциями. В языках общего назначения пагинация реализуется простым использованием операторов OFFSET и LIMIT в SQL-запросе к базе данных. В языке запросов 1С оператора OFFSET нет, поэтому всем приходится решать эту задачу обходными способами. Один из таких обходных способов представлен в этой статье.

Предпосылки разработки методов API с пагинацией

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

Весь необходимый API был описан в формате Swagger (OpenAPI) руководителем проекта разработки сайта, его методы мы реализовали с помощью HTTP-сервисов 1С.

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

С таймаутами заморачиваться не стали, т.к. они и так были установлены достаточно большими, по 300 секунд.

Решили сделать версию 2 того же метода, но уже с возможностью пагинации.

 

Особенности реализации пагинации средствами 1С

При разработке методов с пагинацией нужно учитывать следующие особенности:

  1. В языке запросов 1С нет оператора OFFSET, соответственно, смещение записей для получения определённой порции данных нужно реализовать как-то иначе.
    Ограничить количество записей можно с помощью оператора ВЫБРАТЬ ПЕРВЫЕ {количество объектов в порции}, тут всё очевидно.
    Разве что количество объектов в порции придётся подставлять через СтрШаблон(), СтрЗаменить() или конкатенацию.
    Но как выбрать только записи, начиная с определённой?
    Логичным решением выглядит нумерация записей и последующий отбор по номеру.
    В запросах 1С доступна функция АВТОНОМЕРЗАПИСИ(), которая последовательно присваивает номер записи, начиная с 1, полю с вызовом этой функции.
    А дальше по этому номеру можно отобрать нужную порцию данных.
    Это позволит не выбирать все данные с последующим получением нужных данных в коде, например, по индексам, а получать сразу готовую коллекцию записей с помощью запроса.
     
  2. Запросы к методу с одними и теми же полями "limit" (количество объектов в порции данных) и "next"* (номер первого объекта следующей порции) в теле запроса всегда** должны возвращать один и тот же набор объектов.
    * Названия полей приведены так, как они указаны у нас, вы можете их называть, разумеется, на ваше усмотрение.
    ** Передача тела запроса предполагает запрос POST, т.е. об идемпотентности тут речи нет, но метод, возвращающий разные результаты при одних и тех же параметрах запроса, должен вызывать вопросы у клиента. Для большей очевидности (в плане ожидания идемпотентности) можно было бы реализовать метод GET с параметрами в строке запроса, но мы пошли по пути POST с телом JSON.

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

    Хотя левое соединение с другими таблицами может приводить к увеличению количества записей, изначально было не вполне очевидно, что возвращаемое методом количество записей может быть больше запрашиваемого.
    Чтобы этого избежать, основные данные предварительно нужно получать отдельно в запрашиваемом количестве и только потом связывать с дополнительными данными. В последней порции данных может быть меньше.
    Из-за того, что данные временных таблиц в общем случае*** упорядочивать нельзя, связывание основных данных с дополнительными нужно выполнять в дополнительном запросе.
    *** Можно в случае использования оператора ВЫБРАТЬ ПЕРВЫЕ.

 

Пример реализации

Часть комментариев добавил для пояснения тех или иных решений, остальные комментарии и описание взяты из фактической реализации.

Многоточием в тексте запросов обозначены прочие поля.

В первом запросе получаем, фактически, все записи таблицы. Дополнительно не оптимизировали, т.к. отрабатывает быстро, да и клиент у этого метода всего один.

 
 Пример функции для получения данных с пагинацией

 

// Возвращает данные товаров с пагинацией для дальнейшего преобразования в JSON.
//
// Ввиду отсутствия в языке запросов 1С аналога оператора OFFSET
// пагинацию через запрос можно сделать только обходными путями, как в коде этой функции:
// сгенерировать номер записи через АВТОНОМЕРЗАПИСИ(), упорядочить данные по номеру записи,
// выбрать нужное количество записей, начиная с указанного номера.
//
// Номенклатуру нужно всегда предварительно получать отдельно,
// чтобы количество возвращаемой номенклатуры реально соответствовало количеству запрошенной номенклатуры,
// а не количеству записей, образованных левым соединением.
//
// Параметры:
//  КоличествоЗаписей - Число - Количество записей, которые нужно вернуть.
//  НачинаяСЗаписи    - Число - Номер записи, начиная с которой нужно вернуть данные.
// 
// Возвращаемое значение:
//  Массив - Массив структур для дальнейшего преобразования в JSON.
//
Функция ПолучитьТоварыСПагинацией(Знач КоличествоЗаписей, Знач НачинаяСЗаписи) Экспорт
	
	// Принимаем за 1000 максимальное количество элементов справочника Номенклатура,
	// которое можно получить за один запрос.
	// При неправильном значении запрошенных записей вернется 1000 записей,
	// а номер первого элемента следующей порции будет возвращен в ответе сервера.
	Если (КоличествоЗаписей = 0) Или (КоличествоЗаписей > 1000) Тогда
		КоличествоЗаписей = 1000;
	КонецЕсли;
	
	// Упорядочить временную таблицу можно только с ограничением количества записей.
	// Устанавливаем какое-нибудь малодостижимое количество.
	Запрос = Новый Запрос;
	Запрос.Текст = СтрШаблон("ВЫБРАТЬ ПЕРВЫЕ 100000
	                         |	АВТОНОМЕРЗАПИСИ() КАК НомерЗаписи,
	                         |	Номенклатура.Ссылка КАК Ссылка,
	                         |	Номенклатура.Код КАК Код,
	                         |	Номенклатура.Наименование КАК Наименование,
	                         |	...
	                         |ПОМЕСТИТЬ ДанныеНоменклатуры
	                         |ИЗ
	                         |	Справочник.Номенклатура КАК Номенклатура
	                         |ГДЕ
	                         |	НЕ Номенклатура.ПометкаУдаления
	                         |	И НЕ Номенклатура.ЭтоГруппа
	                         |
	                         |УПОРЯДОЧИТЬ ПО
	                         |	Код
	                         |;
	                         |
	                         |////////////////////////////////////////////////////////////////////////////////
	                         |ВЫБРАТЬ ПЕРВЫЕ %1
	                         |	ДанныеНоменклатуры.НомерЗаписи КАК НомерЗаписи,
	                         |	ДанныеНоменклатуры.Ссылка КАК Ссылка,
	                         |	ДанныеНоменклатуры.Код КАК Код,
	                         |	ДанныеНоменклатуры.Наименование КАК Наименование,
	                         |	...
	                         |ИЗ
	                         |	ДанныеНоменклатуры КАК ДанныеНоменклатуры
	                         |ГДЕ
	                         |	ДанныеНоменклатуры.НомерЗаписи >= &НачинаяСЗаписи
	                         |
	                         |УПОРЯДОЧИТЬ ПО
	                         |	НомерЗаписи", Формат(КоличествоЗаписей, "ЧГ="));
	Запрос.УстановитьПараметр("НачинаяСЗаписи", НачинаяСЗаписи);
	
	// Для получения нужных записей данные должны быть обязательно предварительно упорядочены.
	// Для временных таблиц это невозможно, поэтому нужные записи выгружаем в таблицу и передаем
	// в следующий запрос, чтобы подтянуть все остальные данные.
	ДанныеЗапрошеннойНоменклатуры = Запрос.Выполнить().Выгрузить();
	
	Запрос.Текст = "ВЫБРАТЬ
	               |	ДанныеЗапрошеннойНоменклатуры.Ссылка КАК Ссылка,
	               |	ДанныеЗапрошеннойНоменклатуры.Код КАК Код,
	               |	ДанныеЗапрошеннойНоменклатуры.Наименование КАК Наименование,
	               |	...
	               |ПОМЕСТИТЬ ДанныеНоменклатуры
	               |ИЗ
	               |	&ДанныеЗапрошеннойНоменклатуры КАК ДанныеЗапрошеннойНоменклатуры
	               |
	               |ИНДЕКСИРОВАТЬ ПО
	               |	Ссылка
	               |;
	               |
	               |////////////////////////////////////////////////////////////////////////////////
	               |// Здесь связь с другими таблицами и получение итогового набора записей.";
	
	Запрос.УстановитьПараметр("ДанныеЗапрошеннойНоменклатуры", ДанныеЗапрошеннойНоменклатуры);
	
	РезультатЗапроса = Запрос.Выполнить();
	
	ВыборкаТоваров = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	Товары = Новый Массив;
	
	Пока ВыборкаТоваров.Следующий() Цикл
		
		// ПолучитьДанныеНоменклатуры() - это функция, возвращающая структуру
		// с данными номенклатуры и связанными с ней данными
		// для дальнейшего преобразования в объект JSON.
		ДанныеТекущейНоменклатуры = ПолучитьДанныеНоменклатуры(ВыборкаТоваров);
		Товары.Добавить(ДанныеТекущейНоменклатуры);
		
	КонецЦикла;
	
	Возврат Товары;
	
КонецФункции

 

пагинация REST API HTTP-сервис

См. также

Оптовая торговля Розничная торговля WEB-интеграция 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Платные (руб)

Онлайн-заказ - это решение для автоматизации процесса оформления заказов на сайте в торговых организациях. Продукт обеспечивает легкое взаимодействие между компанией и клиентами через веб-интерфейс, интегрированный с 1С:Предприятие. Система позволяет снизить операционные расходы, повысить лояльность клиентов и оптимизировать работу отдела продаж.

57600 руб.

26.11.2024    1235    1    1    

4

Сайты и интернет-магазины WEB-интеграция Системный администратор Программист Пользователь Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    18355    20    22    

18

Сайты и интернет-магазины Интеграция WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 Управленческий учет Платные (руб)

Интеграция 1С и Битрикс 24. Разработка имеет двухстороннюю синхронизацию 1С и Bitrix24 задачами. Решение позволяет создавать пользователя в 1С из Битрикс24 и наоборот. Данная разработка технически подходит под все основные конфигурации линейки продуктов 1С:Предприятие 8.3 (платформа начиная с 8.3.23): 1С:Управление торговлей, 1С:Управление Нашей фирмой 3, 1С:Комплексная автоматизация 2, Объединенное решение: Модуль 1С:CRM 3 (3.0.21.3) +1С:ERP Управление предприятием 2. При приобретении предоставляется 1 месяц бесплатных обновлений разработки. Доступна демо-версия продукта с подключением Вашего Битрикс24

7200 руб.

04.05.2021    20564    13    19    

18

WEB-интеграция Программист Бизнес-аналитик Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Оптовая торговля, дистрибуция, логистика ИТ-компания Платные (руб)

Модуль "Экспортер" — это расширение для 1С, предназначенное для автоматизации процессов выгрузки данных. Оно позволяет эффективно извлекать, преобразовывать и передавать данные из систем 1С в интеграционную платформу Spot2D. Подсистема упрощает настройку, снижает количество ручных операций и обеспечивает удобный контроль данных.

14400 руб.

20.12.2024    320    2    0    

5

WEB-интеграция Программист Руководитель проекта Платформа 1С v8.3 Конфигурации 1cv8 1С:Франчайзи, автоматизация бизнеса Платные (руб)

Расширение значительно упрощает написание API на 1С. Веб программисты получают простой и понятный доступ к 1С. Описание API создаётся автоматически и представляется в виде удобном как для человека, так и для программной обработки.

24000 руб.

27.09.2024    2483    1    0    

3
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. lmnlmn 69 09.01.23 01:50 Сейчас в теме
Выглядит неплохо до тех пор пока кто-нибудь пометку удаления на номенклатуру между запросами разных страниц не поставит, али еще чего не учудит.
3. AlekseiAdamov 186 09.01.23 06:50 Сейчас в теме
(1) Я несколько упростил запрос в примере, у нас данные по номенклатуре для сайта берутся из отдельного регистра, куда они попадают по определённым правилам по заданному расписанию.
Понятное дело, что и такой вариант не убережёт от изменения состава страницы.
Тут, скорее, речь о том, что в процессе последовательного получения данных ожидаем, что состав данных ранее принятых страниц не изменился в большую сторону и часть данных оказалась неполученной. Расписание позволяет этого избежать. Но тут уже зависит от конкретных потребностей - в нашем случае данные сайтом запрашиваются несколько раз в сутки, не случится ничего страшного от того, что какая-то номенклатура попадёт на сайт, скажем, через пару часов, а не через 5 минут.
2. nomad_irk 80 09.01.23 06:45 Сейчас в теме
(0)в общем случае, автономерзаписи не гарантирует одинаковую нумерацию записей в двух запросах, разделенных по времени.
Поэтому нумеровать записи необходимо "вручную", т.е. соединяя таблицу саму с собой по условию Т1.ссылка > Т2.Ссылка.
it_depDi; Жолтокнижниг; Diversus; +3 Ответить
4. AlekseiAdamov 186 09.01.23 07:29 Сейчас в теме
(2) Как это помогает избежать проблем, указанных в комментарии (1)?
5. nomad_irk 80 09.01.23 07:45 Сейчас в теме
(4)никак, это две абсолютно разные проблемы.
Нумерация записей "вручную" даст разные результаты только в случае, когда между запросами данных произойдет физическое удаление/добавление элементов
6. Diversus 2330 09.01.23 10:42 Сейчас в теме
(0) Тоже долго мучались с пагинацией для универсального API на базе 1С.
У нас проблема осложнялась тем, что сортировка в запросе может быть произвольной и передавалась в HTTP-запросе и АВТОНОМЕРЗАПИСИ не работает нормально с этим.

Нашли свой универсальный способ работы с пагинацией. Наш запрос основывается на другом. А именно на том, что в SQL есть возможность использовать SKIP и TOP, а в 1С можно использовать только TOP (Первые). Если переложить SKIP исключительно на TOP, то имея задачу:

Исходная задача На языке запросов 1С необходимо с помощью языка запросов выбрать M записей начиная с записи N в справочнике Номенклатура.

Получаем, что-то типа вот такого запроса:

SELECT top N+M * FROM TABLE ORDER BY n
EXCEPT
SELECT top N * FROM TABLE ORDER BY n


При этом сортировка может быть любая, но обязательно должна быть одинаковая в двух запросах.

Если же переложить теперь этот SQL запрос на 1С, то получаем:

ВЫБРАТЬ ПЕРВЫЕ 10 // M
    Номенклатура.Ссылка КАК Ссылка
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ	
    НЕ Номенклатура.Ссылка В
                (ВЫБРАТЬ ПЕРВЫЕ 10 // N
                    Номенклатура.Ссылка КАК Ссылка
                ИЗ
                    Справочник.Номенклатура КАК Номенклатура
                ГДЕ
                    Номенклатура.ЭтоГруппа = ЛОЖЬ
                УПОРЯДОЧИТЬ ПО
                    Номенклатура.Наименование,
                    Ссылка)
    И Номенклатура.ЭтоГруппа = ЛОЖЬ

УПОРЯДОЧИТЬ ПО
    Наименование,
    Ссылка
Показать


И аналогично сортировка может быть любая, но должна совпадать во вложенном запросе и основном.
Конечно, использовать "НЕ В" в условии и запрос не очень хорошо с точки зрения производительности, но фирма 1С не оставила нам выбора.

Это единственный универсальный способ, который удалось найти.
user832283; simy4; DJ_Codebase; KamranV21; NicolasCage; Artem-B; cdiamond; Jeka44; Kawarimi; sevushka; akR00b; ogroup; VitaliyCeban; serg_gres; Bassgood; place.ru; SeiOkami; it_depDi; simgo83; JohnyDeath; DAAbramov; yufan; Жолтокнижниг; user591216_mail_oll; mysm; Созинов; volex; infosoft-v; AlekseiAdamov; minarenko; Lem0n; +31 Ответить
7. AlekseiAdamov 186 09.01.23 13:35 Сейчас в теме
(6) Отлично, большое спасибо за то, что поделились!
Я написал статью только потому, что не нашёл аналогичной. Может, плохо искал.
Так что пусть хоть в комментариях будут альтернативные решения.
9. пользователь 09.01.23 14:33
Сообщение было скрыто модератором.
...
10. Diversus 2330 09.01.23 16:33 Сейчас в теме
(9) Задача пагинации - это разбитие выборки на одинаковые кусочки. Речи о добавлении/удалении записей нет.
it_depDi; yufan; volex; +3 Ответить
11. пользователь 09.01.23 16:37
Сообщение было скрыто модератором.
...
12. AlekseiAdamov 186 09.01.23 16:56 Сейчас в теме
(11) Я писал об этом допущении - всё зависит то того, с какой периодичностью обновляются запрашиваемые данные.
Если брать их напрямую из справочников, которые постоянно редактируются пользователями, такая ситуация возможна.
А если из какой-то отдельной таблицы типа регистра сведений, который заполняется по расписанию, то там вероятность таких ситуаций значительно меньше, особенно если данные обновляются раз в день и клиент у метода всего один.

Собственно, вероятность возникновения изменений данных при последовательном чтении страниц - это не проблема платформы 1С.
Можете погуглить что-нибудь типа этого - обсуждений хватает.

Варианты решения предлагаются разные, например:
1. Принять как должное, что данные меняются.
2. Получать весь набор записей и кэшировать его исходя из предположения, что раз запросили первую страницу, то запросят и последующие.
3. Сравнивать наборы данных в разных страницах и уведомлять клиента в ответе, что за время запроса данные могли измениться и нужно запросить их заново.
4. Заморочиться с использованием курсоров вместо OFFSET + LIMIT.
И т.д.
Bassgood; +1 Ответить
16. пользователь 09.01.23 18:26
Сообщение было скрыто модератором.
...
17. AlekseiAdamov 186 09.01.23 20:10 Сейчас в теме
(16) Смотря что за пользователи. В нашем случае это сайт, который сохраняет данные в свою БД. Из его БД данные не удалятся в случае отсутствия какой-то записи в данных, полученных из API, такая номенклатура просто скроется, а там уже будем разбираться, что сделали с номенклатурой в учётной системе, что на сайте номенклатура скрылась.

Кэшировать можно где угодно в зависимости от задач. Поскольку запрос выполняется к серверу, а из БД данные получает именно сервер, то очевидно, что кэшировать нужно на сервере. А там хоть в Redis скидывайте.
23. siamagic 09.02.23 15:35 Сейчас в теме
(6)
M записей начиная с записи N в справочнике Номенклатура.


дурость полная - делай сравнение по ссылке и однозначно будет упорядочивание без конструкций вида "НЕ Номенклатура.Ссылка В"
24. Diversus 2330 09.02.23 16:45 Сейчас в теме
(23) Маэстро, дабы не разводить демагогию, прошу код в студию!
Учтите, что если запрос будет предоставлен, я попрошу, разные сортировки. Например, по наименованию, потом по коду и т.п.
Т.е. будет задача вида:
M записей начиная с записи N в справочнике Номенклатура с сортировкой номенклатуры по наименованию

Код из моей "дурости" такое может. Достаточно и в первом запросе и в подзапросе сделать одинаковую сортировку и все будет работать.
Сможете ли сделать по другому, чтобы так же гибко было с сортировкой?

PS: Я не претендую на то, что бы мой способ уникальный или единственный. Просто интересно, можно ли это еще как-то сделать, но быстрее?
25. siamagic 09.02.23 19:08 Сейчас в теме
(24) сначала выборка, затем отборы и сортировки вы вообще не понимаете как работает субд
26. Diversus 2330 09.02.23 19:34 Сейчас в теме
(25) Запрос приведите как правильно. Негоже такому специалисту как вы только словами бросаться.
8. minarenko 09.01.23 14:19 Сейчас в теме
(0) на каждую следующую порцию в уникальный код передаем последний полученный
ВЫБРАТЬ ПЕРВЫЕ 1000
	Номенклатура.Ссылка КАК Ссылка
ИЗ
	Справочник.Номенклатура КАК Номенклатура
ГДЕ
	НЕ Номенклатура.ПометкаУдаления
	И НЕ Номенклатура.ЭтоГруппа
	И Номенклатура.Код > &Код

УПОРЯДОЧИТЬ ПО
	Номенклатура.Код,
	Ссылка
Показать
13. AlekseiAdamov 186 09.01.23 17:05 Сейчас в теме
(8) Принципиальных отличий нет - можно сделать и так, и возвращать не номер, а код следующего элемента. Некоторые так и поступают: у Вайлдберриз так возвращается идентификатор первого сборочного задания в следующей порции, если я не путаю.
Обычно всё-таки есть какие-то отборы: в номенклатуре может быть что-то выведенное из ассортимента, какие-то услуги, что-то для внутреннего потребления типа канцтоваров - вряд ли владелец бизнеса захочет всё это тащить на свой сайт, особенно если сайт не просто витрина.
А значения критериев отбора склонны меняться, если это реальная учётная система. В итоге в следующей порции оказывается не 1000 объектов, а меньше.
user1881120; +1 Ответить
15. пользователь 09.01.23 17:29
Сообщение было скрыто модератором.
...
14. пользователь 09.01.23 17:25
Сообщение было скрыто модератором.
...
18. minarenko 10.01.23 05:29 Сейчас в теме
(14)все это также применимо и к offset. Необходимо хранить смещение последней порции и все остальное что перечислили
19. minarenko 10.01.23 05:32 Сейчас в теме
(14)не надо в сторонней системе нумеровать элементы. Получили код последнего элемента АБВ123464651. Чтобы получить следующую порцию этот же код АБВ123464651 и передаем
21. Bassgood 1225 17.01.23 11:49 Сейчас в теме
(14) Делаем код справочника уникальным числовым с автонумерацией (через свойства справочника) или добавляем свой служебный числовой реквизит с реализацией своей автонумерации (судя по всему при записи элементов справочника) - соответственно в запросе мы можем использовать этот числовой реквизит для пагинации.
По-хорошему записи таблицы сначала помечаются на удаление, а уже потом удаляются из нее физически (обычно по регламенту) - при этом можно не фильтровать записи в запросе по пометке на удаление, а передавать этот признак в ответе на запрос в виде булевского поля "is_deleted" - что делать с такими записями на принимающей стороне (скрывать записи, отображать эту пометку, как-то обрабатывать) - дело каждого.
20. agentz 40 10.01.23 22:25 Сейчас в теме
Все решения с пагинацией в 1С не корректны будут с точки зрения СУБД т.к приходится многократно выбирать все данные, а потом фильтровать/соединять.
Я реализовывал через некий кэш в регистре сведений, который был привязан к сессии пользователя и возвращал порции из ТЗ, которую ранее сформировал для него. Затем этот регистр регл.заданием чистился, грубо говоря, если запросов не было в сессии более 15 мин, то чистим данные.

(8) Вопрос актуальности данных между запросами везде останется в любой системе, так что это неизбежное и с этим нужно уметь работать принимающей стороне. Сам ловил, когда запрашивал данные, а в некоторый момент мне часть данных не пришла т.к их удалили за время пока я читал постранично.
Bassgood; JohnyDeath; +2 Ответить
22. Bassgood 1225 17.01.23 12:14 Сейчас в теме
Еще как вариант может быть имеет смысл посмотреть в сторону механизма платформы "Копии базы данных" и свойства запроса "ТребуемоеВремяАктуальностиДанных" (сам его ни разу не использовал и не видел в работе) - то бишь для получения данных на запросы использовать не оперативную рабочую базу (или какой-либо отдельный регистр в ней), а копию базы данных, содержащую только интересующую нас информацию, которая обновляется по заданному нами регламенту или событиям.
27. siamagic 14.02.23 08:07 Сейчас в теме
(26) Берете любой динамический список, сортируете и наблюдаете в профайлере.
думать что хоть один вменяемый разработчик при перелистывании будет запоминать множество пройденных элементов - упоротость.

Как вариант у вас порядок по наименованию от М,N штук

выборка n наименование
из таблица где наименование > M
Упорядочить по наименование

и так можно крутить бесконечные списки
28. Diversus 2330 14.02.23 09:51 Сейчас в теме
(27) Первое. Внимательно посмотрите мой запрос, а потом пишите сообщение в теме. Где в моем запросе " при перелистывании будет запоминать множество пройденных элементов"? В самом запросе меняются только числа M и N и при изменении N (а точнее N = N + M) мы получаем в результате выполнения запроса новую порцию данных.

Второе. То, что вы привели в качестве решения - это не решение. Ваш запрос ничего не делает, да и не запрос это.

Третье. Я тут подумал. Наверное не стоит больше отвечать мне в этом треде. Легче всего видеть вокруг идиотов и "упоротых" и при этом самому ничего толкового не предложить. Так делают только тролли, а так же люди, которые хотят набить побольше стартмани своими сообщениями. При этом сами ничего не публикуют, т.к. их "гениальность" не для таких элементарных вещей.
29. siamagic 14.02.23 11:25 Сейчас в теме
(28)
1. Ваш запрос:
ВЫБРАТЬ ПЕРВЫЕ 10 // M
    Номенклатура.Ссылка КАК Ссылка
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ    
    НЕ Номенклатура.Ссылка В
                (ВЫБРАТЬ ПЕРВЫЕ 10 // N
                    Номенклатура.Ссылка КАК Ссылка
                ИЗ
                    Справочник.Номенклатура КАК Номенклатура
                ГДЕ
                    Номенклатура.ЭтоГруппа = ЛОЖЬ
                УПОРЯДОЧИТЬ ПО
                    Номенклатура.Наименование,
                    Ссылка)
    И Номенклатура.ЭтоГруппа = ЛОЖЬ

УПОРЯДОЧИТЬ ПО
    Наименование,
    Ссылка
Показать


"ВЫБРАТЬ ПЕРВЫЕ 10 // N" - вложенная выборка в запросе = " при перелистывании будет запоминать множество пройденных элементов" = каждый раз будет отбор вначале по этому выборке затем по кривому условию которое не отвечает покрытию индекса.

Поэтому я сразу написал что лучше делать через соединения. Для того чтоб понять разницу надо открыть профайлер.


2.
 ВЫБРАТЬ первые 5
	ПроизводствоБезЗаказа.Ссылка КАК Ссылка,
	ПроизводствоБезЗаказа.Номер КАК Номер,
	ПроизводствоБезЗаказа.Дата КАК Дата
ИЗ
	Документ.ПроизводствоБезЗаказа КАК ПроизводствоБезЗаказа
ГДЕ
	ПроизводствоБезЗаказа.Номер > &Номер

УПОРЯДОЧИТЬ ПО
	Номер
Показать


Популярно - Есть сортировка, значит множество упорядоченно = на любой странице есть мин и макс относительно которых считается следующий лист.

3.Запустите это и то что в 2. на выборке миллиард, далее осознавайте свою тупость.
30. Diversus 2330 14.02.23 13:31 Сейчас в теме
(29) Вы опять приводите примеры, которые не относятся к задаче и оскорбляете не знакомых вам людей.
Вам приводят запрос с сортировкой номенклатуры по наименованию, вы приводите документ "ПроизводствоБезЗаказа" и сортировка по номеру. Норм, чо. Упрощаем задачу и говорим, что все тупые, а siamagic - Д'артаньян :)
Повторю вопрос:
На языке запросов 1С необходимо с помощью языка запросов выбрать M записей начиная с записи N в справочнике Номенклатура.

А потом, я ввожу условие, а теперь тоже самое, но с сортировкой по наименованию. Т.е. задача превращается в:
На языке запросов 1С необходимо с помощью языка запросов выбрать M записей начиная с записи N в справочнике Номенклатура с упорядочиванием по Наименованию.

И вот на этой формулировке резко становится грустно. Контекст этой задачи - выдача результата через API, где упорядочивание может быть любым. Наша задача написать какой-то запрос, который будет универсальным для разных сортировок.
Хотите привести пример? Приведите его по условию моей задачи, а не упрощенному вашему варианту.
См. результаты запроса во вложении. Получите тоже самое другим способом. Было бы интересно.
Прикрепленные файлы:
32. siamagic 14.02.23 14:03 Сейчас в теме
(30) Код для тех ничего не понял для справочника номенклатура
ВЫБРАТЬ ПЕРВЫЕ 24000
	(ПроизводствоБезЗаказа.Наименование) КАК Дата
ПОМЕСТИТЬ ВременнаяТаблица1
ИЗ
	Справочник.Номенклатура КАК ПроизводствоБезЗаказа

УПОРЯДОЧИТЬ ПО
	Дата
;

ВЫБРАТЬ 
	максимум(ВременнаяТаблица1.Дата) КАК Дата
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ
	ВременнаяТаблица1
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ ПЕРВЫЕ 10
	ПроизводствоБезЗаказа.Ссылка КАК Ссылка,
	ВременнаяТаблица.Дата КАК Дата1
ИЗ
	Справочник.Номенклатура КАК ПроизводствоБезЗаказа
		ЛЕВОЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица
		ПО (ПроизводствоБезЗаказа.Наименование > ВременнаяТаблица.Дата)
ГДЕ
not	ВременнаяТаблица.Дата ЕСТЬ NULL

УПОРЯДОЧИТЬ ПО
	наименование
Показать


работает в 55 раз быстрее
31. siamagic 14.02.23 13:51 Сейчас в теме
(30) Какая разница какая таблица и сортировка по какому реквизиту? У меня просто это самая большая таблица.

В тестах ваш запрос я тоже делал на ней. На маленьких данных всей тупости запроса не видно - это не интересно.


Вопрос в пагинации - выдачи чанков в зависимости от отбора и сортировки и действительно глядя на ваше убожество будет грустно.


"Контекст этой задачи - выдача результата через API, где упорядочивание может быть любым" - в вашем запросе явно прописано упорядочивание, впрочем в апи тупо передается поле сортировки и направление, всё тривиально.


ВЫБРАТЬ ПЕРВЫЕ 240000
	(ПроизводствоБезЗаказа.Дата) КАК Дата
ПОМЕСТИТЬ ВременнаяТаблица1
ИЗ
	Документ.ПроизводствоБезЗаказа КАК ПроизводствоБезЗаказа

УПОРЯДОЧИТЬ ПО
	Дата
;

ВЫБРАТЬ 
	максимум(ВременнаяТаблица1.Дата) КАК Дата
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ
	ВременнаяТаблица1
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ ПЕРВЫЕ 10
	ПроизводствоБезЗаказа.Номер КАК Номер,
	ПроизводствоБезЗаказа.Дата КАК Дата,
	ПроизводствоБезЗаказа.Ссылка КАК Ссылка,
	ВременнаяТаблица.Дата КАК Дата1
ИЗ
	Документ.ПроизводствоБезЗаказа КАК ПроизводствоБезЗаказа
		ЛЕВОЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица
		ПО (ПроизводствоБезЗаказа.Дата > ВременнаяТаблица.Дата)
ГДЕ
not	ВременнаяТаблица.Дата ЕСТЬ NULL

УПОРЯДОЧИТЬ ПО
	Дата
Показать


типа так?

Это работает быстрей вашего, но так не делается у нормальных программистов.
33. Diversus 2330 14.02.23 14:21 Сейчас в теме
(31)
"Контекст этой задачи - выдача результата через API, где упорядочивание может быть любым" - в вашем запросе явно прописано упорядочивание, впрочем в апи тупо передается поле сортировки и направление, всё тривиально.


Да, приходят запросы к HTTP-сервису вида:
/hs/lk/api/v1/nomenclature?object_start=1&object_count=10&order_by=name&sort_direction=asc
/hs/lk/api/v1/nomenclature?object_start=1&object_count=10&order_by=code&sort_direction=desc
...

Это можно использовать для вывода в таблицы с постраничной навигацией прямо из базы на HTML.

И хочется эту задачу решить универсальным запросом подсовывая сортировку. Очевидно, что в такой задаче текст запроса должен собираться как-то автоматически и универсально. В нашем варианте, это отрабатывает, мы подсовываем только сортировку, M и N.
Цель - найти оптимальное решение. Повторю - мое решение - это то, что удалось найти. Найдется способ быстрее, буду только рад.

(32)
работает в 55 раз быстрее кто те идиоты что тебе плюсов накидали?

Следи за языком, уважаемый. Токсичность и оскорбления других обычно никогда не работают в плюс.
34. siamagic 14.02.23 14:55 Сейчас в теме
(33)

1. Через odata

2. В моем варианте заменой необходимого реквизита и сортировки тоже все решается

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

"В нашем варианте, это отрабатывает, мы подсовываем только сортировку, M и N." а надо элемент и сортировку
35. Diversus 2330 15.02.23 18:26 Сейчас в теме
(34) Ваше предложение натолкнуло на еще одно решение.
Меняя M и N + поля сортировки, задача решается так же просто.
Пример с запросом, для пагинации по наименованию номенклатуры ниже.
Но увеличение скорости в 55 на наших данных не получается. Плюс-минус с теми же цифрами, что и были.
Скажите пожалуйста, вы в замерах учитывали время на создание временных таблиц? Ведь это тоже надо считать для объективной картины.

ВЫБРАТЬ ПЕРВЫЕ 100 // N
	Номенклатура.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_1
ИЗ
	Справочник.Номенклатура КАК Номенклатура
ГДЕ
	Номенклатура.ЭтоГруппа = ЛОЖЬ

УПОРЯДОЧИТЬ ПО
	Номенклатура.Наименование,
	Ссылка
	
ИНДЕКСИРОВАТЬ ПО
	Ссылка	
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ ПЕРВЫЕ 10 // M
	Номенклатура.Ссылка КАК Ссылка
ИЗ
	Справочник.Номенклатура КАК Номенклатура
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_1 КАК ВТ_1
		ПО (Номенклатура.Ссылка = ВТ_1.Ссылка)
ГДЕ
	ВТ_1.Ссылка ЕСТЬ NULL
	И Номенклатура.ЭтоГруппа = ЛОЖЬ

УПОРЯДОЧИТЬ ПО
	Номенклатура.Наименование,
	Ссылка
Показать


PS: В скринах создание ВТ_1 и основной запрос (правда для других метаданных - для документов которых 14949. Размер порции M = 1000, сдвиг N = 4000 на скринах). Как видите, создание ВТ тоже кушает времени прилично по отношению с основным запросом. Наверное, на огромных базах это будут мелочи, но все таки интересен порядок цифр на ваших данных.
Прикрепленные файлы:
36. siamagic 16.02.23 07:14 Сейчас в теме
(35) Для чистоты эксперимента тестировал на справочнике номенклатура, дальше консоли замер не делал - в консоли время выполнения на 55 отличается смысл планы ковырять? Сервер ms sql "дохлый" , M задавал разный чтоб кэш не отрабатывал.
37. Child0fTheSun 01.09.24 14:58 Сейчас в теме
С АВТОНОМЕРЗАПИСИ() есть проблема с тем, что элементы не всегда нумеруются с 1. Например, мы выполняем запрос, получаем 3 элемента с номерами 1-3, если выполнить заново этот же запрос, то номера уже будут 3-6. Как быть в данной ситуации?
38. rabid_otter 134 09.01.25 12:31 Сейчас в теме
По-моему offset+limit пагинация считается плохим тоном, так как СУБД постоянно приходится перелопачивать offset+limit записей.
Упорядочивайте по коду и ссылке, а в ответе присылается pagination_token - типа base64 закодированное представление ссылки.
Таким образом у вас нет завязки на какой-то пресловутый ID, и вы всегда сможете завязаться на другое поле.
Говорю как бывший 1Сник и gopher с более чем 3летним стажем.

PS: Если конечно бизнесу нужна возможность скакать по произвольным страницам, тогда да придется делать offset+limit
Оставьте свое сообщение