Пагинация в 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-сервис

См. также

Интеграция Альфа Авто 5 / Альфа Авто 6 и AUTOCRM / Инфотек

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

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

36000 руб.

03.08.2020    15750    10    17    

11

Интеграция 1С — Битрикс24. Обмен задачами

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

Интеграция 1С и Битрикс24. Разработка имеет двухстороннюю синхронизацию 1С и Битрикс24 задачами. Решение позволяет создавать пользователя в 1С из Битрикс24 и наоборот. Данная разработка технически подходит под все основные конфигурации линейки продуктов 1С:Предприятие 8.3 (8.3.18.1289). При приобретении предоставляется 1 месяц бесплатных обновлений разработки. Доступна демо-версия продукта с подключением Вашего Битрикс24

5040 руб.

04.05.2021    17558    6    15    

13

Интеграция с сервисом vetmanager

WEB-интеграция Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Внешняя обработка разрабатывалась для загрузки документов из Ветменеджер в 1С: Бухгалтерия 3.0

12000 руб.

02.02.2021    16364    42    49    

23

[Расширение] БОР-Навигатор.Культура

Зарплата Бюджетный учет WEB-интеграция Обмен с ГосИС Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бюджетный учет Платные (руб)

Расширение конфигурации, включающее в себя объекты, необходимые для подготовки и сдачи отчета "Штатная численность" системы "БОР-Навигатор.Культура" в программе "1С:Зарплата и кадры государственного учреждения", редакция 3.1.

8400 руб.

01.02.2019    25746    9    0    

7

Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС

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

Обработка является альтернативой механизму, разработанному фирмой 1С и заполняющему реквизиты контрагента по ИНН или наименованию. Не требуется действующей подписки ИТС. Вызывается как внешняя дополнительная обработка, т.е. используется, непосредственно, из карточки контрагента. Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС (egrul.nalog.ru) для БП 2.0, БП 3.0, БГУ 1.0, БГУ 2.0, УТ 10.3, УТ 11.x, КА 1.1, КА 2.x, УПП 1.x, ERP 2.x, УНФ 1.5, УНФ 1.6, УНФ 3.0, ДО 2.1

2400 руб.

28.04.2016    88593    160    215    

318
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. lmnlmn 69 09.01.23 01:50 Сейчас в теме
Выглядит неплохо до тех пор пока кто-нибудь пометку удаления на номенклатуру между запросами разных страниц не поставит, али еще чего не учудит.
3. AlekseiAdamov 165 09.01.23 06:50 Сейчас в теме
(1) Я несколько упростил запрос в примере, у нас данные по номенклатуре для сайта берутся из отдельного регистра, куда они попадают по определённым правилам по заданному расписанию.
Понятное дело, что и такой вариант не убережёт от изменения состава страницы.
Тут, скорее, речь о том, что в процессе последовательного получения данных ожидаем, что состав данных ранее принятых страниц не изменился в большую сторону и часть данных оказалась неполученной. Расписание позволяет этого избежать. Но тут уже зависит от конкретных потребностей - в нашем случае данные сайтом запрашиваются несколько раз в сутки, не случится ничего страшного от того, что какая-то номенклатура попадёт на сайт, скажем, через пару часов, а не через 5 минут.
2. nomad_irk 71 09.01.23 06:45 Сейчас в теме
(0)в общем случае, автономерзаписи не гарантирует одинаковую нумерацию записей в двух запросах, разделенных по времени.
Поэтому нумеровать записи необходимо "вручную", т.е. соединяя таблицу саму с собой по условию Т1.ссылка > Т2.Ссылка.
it_depDi; Жолтокнижниг; Diversus; +3 Ответить
4. AlekseiAdamov 165 09.01.23 07:29 Сейчас в теме
(2) Как это помогает избежать проблем, указанных в комментарии (1)?
5. nomad_irk 71 09.01.23 07:45 Сейчас в теме
(4)никак, это две абсолютно разные проблемы.
Нумерация записей "вручную" даст разные результаты только в случае, когда между запросами данных произойдет физическое удаление/добавление элементов
6. Diversus 2307 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С не оставила нам выбора.

Это единственный универсальный способ, который удалось найти.
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; +27 Ответить
7. AlekseiAdamov 165 09.01.23 13:35 Сейчас в теме
(6) Отлично, большое спасибо за то, что поделились!
Я написал статью только потому, что не нашёл аналогичной. Может, плохо искал.
Так что пусть хоть в комментариях будут альтернативные решения.
9. пользователь 09.01.23 14:33
Сообщение было скрыто модератором.
...
10. Diversus 2307 09.01.23 16:33 Сейчас в теме
(9) Задача пагинации - это разбитие выборки на одинаковые кусочки. Речи о добавлении/удалении записей нет.
it_depDi; yufan; volex; +3 Ответить
11. пользователь 09.01.23 16:37
Сообщение было скрыто модератором.
...
12. AlekseiAdamov 165 09.01.23 16:56 Сейчас в теме
(11) Я писал об этом допущении - всё зависит то того, с какой периодичностью обновляются запрашиваемые данные.
Если брать их напрямую из справочников, которые постоянно редактируются пользователями, такая ситуация возможна.
А если из какой-то отдельной таблицы типа регистра сведений, который заполняется по расписанию, то там вероятность таких ситуаций значительно меньше, особенно если данные обновляются раз в день и клиент у метода всего один.

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

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

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


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

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

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

УПОРЯДОЧИТЬ ПО
	Номенклатура.Код,
	Ссылка
Показать
13. AlekseiAdamov 165 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 1425 17.01.23 11:49 Сейчас в теме
(14) Делаем код справочника уникальным числовым с автонумерацией (через свойства справочника) или добавляем свой служебный числовой реквизит с реализацией своей автонумерации (судя по всему при записи элементов справочника) - соответственно в запросе мы можем использовать этот числовой реквизит для пагинации.
По-хорошему записи таблицы сначала помечаются на удаление, а уже потом удаляются из нее физически (обычно по регламенту) - при этом можно не фильтровать записи в запросе по пометке на удаление, а передавать этот признак в ответе на запрос в виде булевского поля "is_deleted" - что делать с такими записями на принимающей стороне (скрывать записи, отображать эту пометку, как-то обрабатывать) - дело каждого.
20. agentz 40 10.01.23 22:25 Сейчас в теме
Все решения с пагинацией в 1С не корректны будут с точки зрения СУБД т.к приходится многократно выбирать все данные, а потом фильтровать/соединять.
Я реализовывал через некий кэш в регистре сведений, который был привязан к сессии пользователя и возвращал порции из ТЗ, которую ранее сформировал для него. Затем этот регистр регл.заданием чистился, грубо говоря, если запросов не было в сессии более 15 мин, то чистим данные.

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

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

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

и так можно крутить бесконечные списки
28. Diversus 2307 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 2307 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 2307 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 2307 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 задавал разный чтоб кэш не отрабатывал.
Оставьте свое сообщение