стандарт 644

ID: #std644

# Обеспечение совместимости библиотек

#### 1.

При разработке библиотек обеспечивайте обратную совместимость
между версиями в пределах одной [#std483: подредакции](https://v8std.ru/std/483/)

Например, версии `2.0.1`, `2.0.2`, `2.0.5` должны быть совместимы друг с другом.
Следующая подредакция (`2.1`) может содержать изменения,
которые нарушают совместимость.

Совместимость снижает затраты на обновление библиотек в конфигурациях-потребителях:

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

#### 1.1.

Полный номер версии библиотеки должен однозначно показывать
характер изменений и совместимость.

      Что изменилось в новой версии
      Редакция
      Подредакция
      Версия
      Сборка
      Архитектурные изменения, нарушена совместимость (есть инструкция по переходу)
        Да
        Да
        Нет
        Нет
      Новые функции
        Да
        Да
        Да
        Нет
      Исправлены ошибки
        Да
        Да
        Да
        Да

Номер версии:

```mermaid
%%{init: {"flowchart": {"nodeSpacing": 4, "rankSpacing": 1, "curve": "linear"}} }%%
flowchart LR
    D1["2"]:::digit --> P1["."]:::dot --> D2["3"]:::digit --> P2["."]:::dot --> D3["5"]:::digit --> P3["."]:::dot --> D4["2"]:::digit
    H1["Редакция"]:::hint --> S1[" "]:::spacer --> H2["Подредакция"]:::hint --> S2[" "]:::spacer --> H3["Версия"]:::hint --> S3[" "]:::spacer --> H4["Сборка"]:::hint

    classDef digit font-weight:400,font-size:24px,padding:0px
    classDef dot fill:transparent,stroke:transparent,font-weight:900,font-size:64px
    classDef hint fill:transparent,stroke:transparent,font-size:32px,font-weight:600
    classDef spacer fill:transparent,stroke:transparent,color:transparent

    linkStyle 0,1,2,3,4,5,6,7,8,9,10,11 stroke:transparent,stroke-width:0px,fill:transparent
```

Расшифровка:

1. `Редакция` (1-я цифра) — существенно нарушена совместимость,
   есть серьезные архитектурные или «знаковые» изменения.
2. `Подредакция` (2-я цифра) — нарушена совместимость,
   требуется инструкция по переходу,
   без адаптации конфигурация неработоспособна;
   также допускается удаление устаревших объектов метаданных.
3. `Версия` (3-я цифра) — только новые возможности
   для пользователей и/или разработчиков;
   возможна механическая автозаливка метаданных;
   инструкция по переходу не обязательна,
   без нее работоспособность сохраняется.
4. `Сборка` (4-я цифра) — только исправления ошибок;
   возможна механическая автозаливка метаданных.

Исключения, которые можно согласовать заранее с потребителями:

- изменения законодательства:
  если следующая версия еще не опубликована,
  допускается выпуск исправительных сборок для всех поддерживаемых веток,
  даже при добавлении функций или нарушении совместимости;
вынужденное нарушение должно быть описано в документации по правилам [раздела 1.8](https://v8std.ru/std/644/#18)
  и обязательно к отработке;
- LTS-версии:
  в исправительные релизы таких версий могут входить
  не только исправления ошибок и законодательные изменения,
  но и отдельные важные доработки,
  даже если они добавляют функции или нарушают совместимость.

Удаление устаревших объектов метаданных выполняйте по графику:

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

В документации к «концу года» отмечайте,
что версия обязательна для перехода,
чтобы гарантировать перенос или очистку данных для реструктуризации.

Недопустимо требовать от типовых решений обязательный переход
чаще одного раза в год суммарно по всем библиотекам.

#### 1.2.

Если библиотека содержит несколько [#std543: функциональных подсистем](https://v8std.ru/std/543/)
нарушение совместимости хотя бы в одной из них
требует увеличения номера подредакции (вторая цифра).

#### 1.3.

Если совместимость незапланированно нарушена
в третьей или четвертой цифре версии,
релиз следует отозвать,
устранить нарушение и выпустить исправленный релиз.

#### 1.4.

Аналогично, незапланированное добавление новых функций
в четвертой цифре версии также требует отзыва релиза
и выпуска исправленного.

#### 1.5.

Для обеспечения совместимости:

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

Требования обратной совместимости имеют приоритет
над стандартами:

- [#std474: Имя, синоним, комментарий](https://v8std.ru/std/474/)
- [#std647: Имена процедур и функций](https://v8std.ru/std/647/)

#### 1.6.

К программному интерфейсу библиотеки относятся объекты,
предназначенные для использования в прикладном коде:

- имена, состав параметров и поведение экспортных процедур и функций,
размещенных в [#std455: разделе «Программный интерфейс»](https://v8std.ru/std/455/)
- имена, состав параметров и поведение всех экспортных процедур
[#std553: переопределяемых общих модулей](https://v8std.ru/std/553/)
- имена ролей и элементов стилей;
- имена объектов метаданных
  (включая реквизиты, табличные части и т.п.),
  к которым допускается прямое обращение из прикладного кода или запросов.

#### 1.7.

Совместимость не нарушается при расширении интерфейса
в третьей цифре версии. Допустимо:

- добавить новую функцию в программный модуль;
- добавить процедуру в переопределяемый модуль;
- добавить новый необязательный параметр в конец списка параметров;
- добавить новый реквизит в справочник, регистр и т.п.,
  если библиотека допускает к ним прямые обращения.

При этом:

- новое API и расширение параметров существующего API
  недопустимы в исправительных релизах (четвертая цифра);
- даже при неизменной сигнатуре,
  изменение поведения процедуры/функции — это нарушение совместимости
  (допустимо только во второй цифре).

Пример: функция `Сумма(а, б)` начала вычислять разность.

#### 1.8.

Во всех случаях, когда по [разделу 1](https://v8std.ru/std/644/#1) допустим отказ от совместимости
документируйте все изменения,
которые нарушают совместимость.

Сопроводительная документация должна содержать инструкции
по адаптации конфигураций-потребителей.

Примеры формулировок:

- общий модуль `ВнешниеЗадачиСервер` переименован в `ВнешниеЗадачи`;
  нужно заменить обращения к модулю в коде конфигурации;
- процедура `УстановитьПроизвольныйЗаголовокПриложения`
  общего модуля `СтандартныеПодсистемыКлиент`
  переименована в `УстановитьРасширенныйЗаголовокПриложения`;
  нужно заменить обращения в коде;
- отчет `СправкаПоИсполнительскойДисциплине` удален;
  вместо него используйте одноименный вариант отчета `Задачи`;
  нужно заменить обращения в коде и метаданных;
- в общий модуль `ЗащитаПерсональныхДанныхПереопределяемый`
  нужно добавить процедуру
  `ДополнитьДанныеОрганизацииОператораПерсональныхДанных`,
  перенеся ее из поставки библиотеки;
- хранение предмета взаимодействий перенесено из реквизита документа
  в реквизит `Предмет` регистра сведений `ПредметыПапкиВзаимодействий`;
  нужно заменить обращения к реквизиту `Предмет` документов
  на реквизит `Предмет` регистра.

#### 1.9.

Размещайте программный интерфейс библиотеки
только в общих модулях,
а не в модулях объектов, менеджеров, наборов записей и т.п.

#### 2.1.

Разделяйте программный интерфейс
и служебные процедуры/функции:

- в разных разделах одного модуля;
- или в разных общих модулях.

Если интерфейс и служебная реализация разнесены по разным модулям,
для служебного модуля используйте постфикс `Служебный` (`Internal`).

Например:

- `ОбменСообщениями`, `ОбменСообщениямиКлиент` — программный интерфейс подсистемы;
- `ОбменСообщениямиСлужебный` — служебная реализация,
  не предназначенная для использования в коде конфигурации-потребителя.

Такой подход позволяет:

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

#### 2.2.

Раздел `Программный интерфейс` может содержать
процедуры и функции для конкретных потребителей
из других подсистем или библиотек.

Выделяйте их в отдельный подраздел
`Для вызова из других подсистем`,
оформленный областью `ДляВызоваИзДругихПодсистем`
(англ. `InterfaceImplementation`).

Внутри подраздела группируйте код комментариями
по имени потребителя.
Подробнее: [#std551: Разработка конфигураций с повторным использованием общего кода и объектов метаданных](https://v8std.ru/std/551/)

Пример:

```bsl
#Область ПрограммныйИнтерфейс
// Код процедур и функций

#Область ДляВызоваИзДругихПодсистем

// СтандартныеПодсистемы.ГрупповоеИзменениеОбъектов
// Код процедур и функций
// Конец СтандартныеПодсистемы.ГрупповоеИзменениеОбъектов

// ТехнологияСервиса.ВыгрузкаЗагрузкаДанных
// Код процедур и функций
// Конец ТехнологияСервиса.ВыгрузкаЗагрузкаДанных

#КонецОбласти

#КонецОбласти
```

Англоязычный вариант:

```bsl
#Region Public
// Enter code here.

#Region InterfaceImplementation

// StandardSubsystems.BatchObjectModification
// Enter code here.
// End StandardSubsystems.BatchObjectModification

// SaaSTechnology.DataExportImport
// Enter code here.
// End SaaSTechnology.DataExportImport

#EndRegion

#EndRegion
```

#### 3.

Практические рекомендации для сохранения совместимости API
при активном развитии библиотеки.

#### 3.1.

Если нужно переименовать или удалить экспортную функцию/процедуру,
оставьте прежнюю реализацию,
пометьте ее как устаревшую
(англоязычный маркер — `Deprecated`),
и добавьте новую функцию с новым именем.

```bsl
#Область УстаревшиеПроцедурыИФункции

// Устарела: Следует использовать функцию ПересчитатьПоКурсу
// ...
Функция ПересчитатьИзВалютыВВалюту(
    Сумма,
    ВалютаНач,
    ВалютаКон,
    ПоКурсуНач,
    ПоКурсуКон,
    ПоКратностьНач = 1,
    ПоКратностьКон = 1) Экспорт

...

#КонецОбласти
```

Устаревшие функции переносите в область
`УстаревшиеПроцедурыИФункции` (`Deprecated`)
внутри `ПрограммныйИнтерфейс`.

Для процедур и функций в области `УстаревшиеПроцедурыИФункции`
допустимы отклонения от других стандартов разработки.

По каждой устаревшей функции добавляйте
в сопроводительную документацию рекомендацию по замене.

#### Проверки
[#v8cs:deprecated-procedure-outside-deprecated-region](https://v8std.ru/diagnostics/v8-code-style/deprecated-procedure-outside-deprecated-region/)

#### 3.2.

Если исправление ошибки меняет поведение экспортной функции,
часто лучше оставить старую реализацию как устаревшую,
а исправленную вынести в новый API.

Это сохраняет работоспособность прикладного кода,
который уже опирается на старое поведение.

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

Типовой риск: вызывающий код при некорректных параметрах
ожидает `Неопределено`, а после «исправления» функция
начинает выбрасывать исключение.

#### 3.3.

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

```bsl
Функция ПересчитатьИзВалютыВВалюту(
    Сумма,
    ВалютаНач,
    ВалютаКон,
    ПоКурсуНач,
    ПоКурсуКон,
    ПоКратностьНач = 1,
    ПоКратностьКон = 1) Экспорт
```

Если параметров много,
используйте последним параметр типа `Структура`:

```bsl
Функция ПересчитатьИзВалютыВВалюту(
    Сумма,
    ВалютаНач,
    ВалютаКон,
    ПоКурсуНач,
    ПоКурсуКон,
    ПараметрыПересчета = Неопределено) Экспорт
```

#### 3.4.

Параметры типа `Структура` используйте также
для совместимости интерфейса,
через который библиотека обращается
к объектам конфигурации-потребителя.

```bsl
Процедура ПриОпределенииНастроек(Настройки) Экспорт
    Настройки.ВыводитьОписания = Истина;
    Настройки.События.ПриСозданииНаСервере = Истина;
    Настройки.... = ...;
КонецПроцедуры
```

Так библиотека может добавлять новые режимы и события
без обязательного добавления «пустых заглушек»
во всех конфигурациях-потребителях.

#### 3.5.

Чтобы прикладной код не зависел от деталей реализации библиотеки,
избегайте прямых обращений к ее объектам метаданных.

Предоставляйте специализированные экспортные функции API,
через которые потребитель получает нужные данные.

Вместо прямого запроса к библиотечному регистру
в коде конфигурации-потребителя:

```bsl
Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ
    |   ОбластиДанных.Представление
    |ИЗ
    |   РегистрСведений.ОбластиДанных КАК ОбластиДанных
    |ГДЕ
    |   ОбластиДанных.ОбластьДанных = &ОбластьДанных";
Запрос.УстановитьПараметр("ОбластьДанных", ПараметрыСеанса.ОбластьДанныхЗначение);
ТаблицаОбластейДанных = Запрос.Выполнить().Выгрузить();
ИмяПриложения = ?(ТаблицаОбластейДанных.Количество() = 0, "", ТаблицаОбластейДанных.Получить(0).Получить(0));
```

используйте библиотечную функцию:

```bsl
ИмяПриложения = РаботаВМоделиСервиса.ИмяПриложения();
```

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

#### 3.6.

Чтобы скрывать детали реализации от потребителя,
размещайте программный интерфейс в обычном общем модуле,
а не в специализированном (`ПовтИсп`, `ВызовСервера`).

Например, если экспортная функция сначала была в `ПовтИсп`,
а позже переносится в обычный модуль,
потребителю придется менять вызовы.

Чтобы этого избежать,
сразу размещайте экспортную функцию в обычном модуле
(в разделе `ПрограммныйИнтерфейс`),
а специализированные модули используйте как внутренние.

Также модули `ВызовСервера` должны отвечать требованиям:

- [#std678: безопасности](https://v8std.ru/std/678/)
- [#std487: минимизации данных, передаваемых между клиентом и сервером](https://v8std.ru/std/487/)

Их проще развивать,
когда они служебные,
не содержат программный интерфейс
и не являются переопределяемыми.

#### 4.

Для контроля изменений программного интерфейса
в новых версиях библиотек
используйте приложенную обработку:

- [Контроль изменения программного интерфейса на ИТС(zip)](https://its.1c.ru/db/files/1CITS/EXE/V8Std/Контрольизмененияпрограммногоинтерфейса/Контрольизмененияпрограммногоинтерфейса.zip)

#### См. также

- [#std483: Нумерация редакций и версий](https://v8std.ru/std/483/)
- [#std455: Структура модуля](https://v8std.ru/std/455/)
- [#std469: Правила создания общих модулей](https://v8std.ru/std/469/)
- [#std474: Имя, синоним, комментарий](https://v8std.ru/std/474/)
- [#std551: Разработка конфигураций с повторным использованием общего кода и объектов метаданных](https://v8std.ru/std/551/)
- [#std553: Переопределяемые и поставляемые объекты библиотеки](https://v8std.ru/std/553/)
- [#std647: Имена процедур и функций](https://v8std.ru/std/647/)

#### Проверки
[#bslls:CachedPublic](https://v8std.ru/diagnostics/bslls/CachedPublic/)

[#acc:277](https://v8std.ru/diagnostics/acc/277/)
[#acc:278](https://v8std.ru/diagnostics/acc/278/)
[#acc:458](https://v8std.ru/diagnostics/acc/458/)
[#acc:468](https://v8std.ru/diagnostics/acc/468/)
[#acc:469](https://v8std.ru/diagnostics/acc/469/)
[#acc:473](https://v8std.ru/diagnostics/acc/473/)
[#acc:474](https://v8std.ru/diagnostics/acc/474/)
[#acc:475](https://v8std.ru/diagnostics/acc/475/)
[#acc:476](https://v8std.ru/diagnostics/acc/476/)
#### Источник

https://its.1c.ru/db/v8std#content:644

При разработке библиотек обеспечивайте обратную совместимость между версиями в пределах одной #std483: подредакции.

Недопустимый вызов служебной процедуры или функции другой подсистемы. АПК:277

Недопустимый вызов служебного программного интерфейса. АПК:278

Устаревшая процедура (функция) расположена вне области "УстаревшиеПроцедурыИФункции". АПК:458

Экспортная процедура (функция) в области "ПрограммныйИнтерфейс" в общем модуле с повторным использованием. АПК:468

В служебном общем модуле присутствует область "ПрограммныйИнтерфейс". АПК:469

Область "ДляВызоваИзДругихПодсистем" не входит в область "ПрограммныйИнтерфейс". АПК:473

В комментарии внутри области "ДляВызоваИзДругихПодсистем" не указана подсистема-потребитель. АПК:474

В комментарии внутри области "ДляВызоваИзДругихПодсистем" указана несуществующая подсистема. АПК:475

Внутри области "ДляВызоваИзДругихПодсистем" не найден закрывающий комментарий "// Конец ... ". АПК:476

Кеширование программного интерфейса BSLLS:CachedPublic

Устаревшая процедура (функция) расположена вне области "УстаревшиеПроцедурыИФункции" (deprecated-procedure-outside-deprecated-region)

Структура модуля #std455

Правила создания общих модулей #std469

Имя, синоним, комментарий #std474

Нумерация редакций и версий #std483

Минимизация количества серверных вызовов и трафика #std487

Использование подсистем #std543

Разработка конфигураций с повторным использованием общего кода и объектов метаданных #std551

Переопределяемые и поставляемые объекты библиотеки #std553

Имена процедур и функций #std647

Безопасность прикладного программного интерфейса сервера #std678

Обеспечение совместимости библиотек #std644


стандарт 647

ID: #std647

# Имена процедур и функций

#### 1.

Чем лучше имена - тем проще читать код. Хорошо выбранное имя процедуры и имена параметров описывают её смысл лучше, чем комментарии. Если имя подобрать сложно - возможно, уже есть проблема в архитектуре решения. Если самодокументирующееся имя придумать легко - все спроектировано верно.

См. [#std453: Описание процедур и функций](https://v8std.ru/std/453/)

#### 2.

Имена процедур, функций и параметров берите от терминов предметной области. Из имени должно быть понятно назначение. Старайтесь выбирать говорящие (самодокументирующиеся) имена.

См. [#std640: Параметры процедур и функций](https://v8std.ru/std/640/)

#### Неправильно

```bsl
Функция ВыполнитьПроверку(Параметр1, Рекв, ТЗ)
Функция ПолучитьМассивыРеквизитов(ХозяйственнаяОперация, МассивВсехРеквизитов, МассивРеквизитовОперации)
```

#### Правильно

```bsl
Функция РеквизитОбъектаЗаданногоТипа(Объект, ИмяРеквизита, ТипЗначения)
Функция ЗаполнитьИменаРеквизитовПоХозяйственнойОперации(ХозяйственнаяОперация, ИменаВсеРеквизиты, ИменаРеквизитыОперации)
```

#### 3.

Формируйте имена так:

- Удалите пробелы между словами.
- Каждое новое слово напишите с большой буквы.
- Предлоги и местоимения пишите большими буквами.

#### 4.

Не используйте типы в названиях процедур и функций. Использовать можно только если без использования неясно название метода.

#### Неправильно

```bsl
Функция ПолучитьМассивРолейСПравомДобавления()
Функция ПолучитьСтруктуруДополнительныхНастроек()
```

#### Правильно

```bsl
Функция ИменаРолейСПравомДобавления()
Функция ДополнительныеНастройки()
```

#### 5.

Имена процедур берите от неопределенной формы глагола. От сути выполняемого действия.

#### Неправильно

```bsl
Процедура ЗагрузкаКонтрагента()
```

#### Правильно

```bsl
Процедура ЗагрузитьКонтрагента()
```

#### 6.1.

Имена функций берите от описания возвращаемого значения.

#### Неправильно

```bsl
Функция ПолучитьПолноеИмя()
Функция СоздатьПараметрыЗаполненияЦенПоставщика()
Функция ОпределитьДатуНачалаСеанса()
```

#### Правильно

```bsl
Функция ПолноеИмя()
Функция НовыеПараметрыЗаполненияЦенПоставщика()
Функция ДатаНачалаСеанса()
```

#### 6.2.

Если функция создает какой-то объект, назовите его со слова `Новый`.

#### Неправильно

```bsl
Функция ДобавитьПолеФормы()
Функция СоздатьЭлементСправочникаФайлы()
Функция ПолучитьТаблицуКоманд()
```

#### Правильно

```bsl
Функция НовоеПолеФормы()
Функция НовыйЭлементСправочникаФайлы()
Функция НоваяТаблицаКоманд()
```

#### 6.3.

Если функция выполняет проверку, назовите ее со слова `Это` или используйте причастие.

#### Неправильно

```bsl
Функция ПроверитьПроведенностьДокумента()
Функция ПроверитьИзменениеРеквизитовДокумента()
Функция ВнешняяЗадача()
```

#### Правильно

```bsl
Функция ДокументПроведен()
Функция РеквизитыДокументыИзменены()
Функция ЭтоВнешняяЗадача()
```

#### 6.4.

Если для понимания назначения функции важно каким образом было получено возвращаемое значение, назовите ее от глагола в неопределенной форме.

#### Правильно

```bsl
Функция ВыбратьДанныеПоПравилу(Правило, ПользовательскиеНастройки)
Функция ПреобразоватьДанныеПоПравилу(НаборыДанных, ПараметрыПреобразования)
```

#### 6.5.

Если функция используется как процедура, ее действие - основная задача, ее результат - побочный эффект, называйте функции как процедуры. Используйте глагол неопределенной формы. Например, возвращает признак выполненного действия.

#### Правильно

```bsl
Функция РазрешитьРедактированиеРеквизитовОбъекта(Форма)
```

#### Проверки
[#bslls:FunctionNameStartsWithGet](https://v8std.ru/diagnostics/bslls/FunctionNameStartsWithGet/)

[#acc:307](https://v8std.ru/diagnostics/acc/307/)
#### Источник

https://its.1c.ru/db/v8std#content:647

Чем лучше имена - тем проще читать код. Хорошо выбранное имя процедуры и имена параметров описывают её смысл лучше, чем комментарии. Если имя подобрать сложно - возможно, уже есть...

Название процедуры (функции) содержит описание типов принимаемых параметров или возвращаемых значений. АПК:307

Имя функции не должно начинаться с "Получить" BSLLS:FunctionNameStartsWithGet

Описание процедур и функций #std453

Параметры процедур и функций #std640

Имена процедур и функций #std647


стандарт 648

ID: #std648

# Ответственное чтение данных

#### 1.

Ответственным считается любое чтение, по результатам которого:

- изменяются данные в информационной базе;
- принимаются бизнес-решения, влияющие на последующие изменения.

#### 1.1.

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

Типичные сценарии:

- чтение данных при проведении с последующим формированием движений;
- чтение для целостной передачи во внешнюю систему;
- групповая обработка и реструктуризация данных при обновлениях.

Для ссылочных объектов перед изменением данных, как правило, дополнительно используйте объектные блокировки.
См. [#std490: Блокировка данных объекта для редактирования из кода](https://v8std.ru/std/490/)

#### Неправильно

```bsl
// 1. Прочитать регистр сведений
Запрос = Новый Запрос(
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |   ЗаметкиПоПредмету.КоличествоЗаметок КАК КоличествоЗаметок
    |ИЗ
    |   РегистрСведений.ЗаметкиПоПредмету КАК ЗаметкиПоПредмету
    |ГДЕ
    |   ЗаметкиПоПредмету.Предмет = &Предмет");
Запрос.УстановитьПараметр("Предмет", ПредметЗаметок);
Выборка = Запрос.Выполнить().Выбрать();

КоличествоЗаметок = 0;
Если Выборка.Следующий() Тогда
    КоличествоЗаметок = Выборка.КоличествоЗаметок;
КонецЕсли;

// 2. Записать в регистр сведений
НаборЗаписей = РегистрыСведений.ЗаметкиПоПредмету.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Предмет.Установить(ПредметЗаметок);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Предмет = ПредметЗаметок;
НоваяЗапись.КоличествоЗаметок = КоличествоЗаметок + 1;
НаборЗаписей.Записать();
```

#### Правильно

```bsl
// 1. Начать транзакцию для пакета из чтения и записи
НачатьТранзакцию();

Попытка
    // 2. Установить исключительную блокировку на интересующий диапазон записей
    БлокировкаДанных = Новый БлокировкаДанных;
    ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрСведений.ЗаметкиПоПредмету");
    ЭлементБлокировки.УстановитьЗначение("Предмет", ПредметЗаметок);
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    БлокировкаДанных.Заблокировать();

    // 3. Прочитать данные
    Запрос = Новый Запрос(
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ
        |   ЗаметкиПоПредмету.КоличествоЗаметок КАК КоличествоЗаметок
        |ИЗ
        |   РегистрСведений.ЗаметкиПоПредмету КАК ЗаметкиПоПредмету
        |ГДЕ
        |   ЗаметкиПоПредмету.Предмет = &Предмет");
    Запрос.УстановитьПараметр("Предмет", ПредметЗаметок);
    Выборка = Запрос.Выполнить().Выбрать();

    КоличествоЗаметок = 0;
    Если Выборка.Следующий() Тогда
        КоличествоЗаметок = Выборка.КоличествоЗаметок;
    КонецЕсли;

    // 4. Записать данные
    НаборЗаписей = РегистрыСведений.ЗаметкиПоПредмету.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Предмет.Установить(ПредметЗаметок);
    НоваяЗапись = НаборЗаписей.Добавить();
    НоваяЗапись.Предмет = ПредметЗаметок;
    НоваяЗапись.КоличествоЗаметок = КоличествоЗаметок + 1;
    НаборЗаписей.Записать();

    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;
```

#### 1.2.

В ряде задач ответственное чтение не требуется.

Например:

- получение данных динамическими списками;
- поиск данных;
- формирование большинства отчетов;
- чтение условно постоянной информации (например, учетной политики, служебных констант);
- действия в монопольных сценариях (обновление и первичное заполнение ИБ);
- действия с персональными данными, где конкурентный доступ практически исключен;
- мобильное приложение, где конкурентная работа маловероятна.

#### 1.3.

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

Это относится, например, к обработчикам:

- [#std464: Обработчик события ПередЗаписью](https://v8std.ru/std/464/)
- [#std465: Обработчик события ПриЗаписи](https://v8std.ru/std/465/)
- [#std752: Обработчик события ПередУдалением](https://v8std.ru/std/752/)

#### 2.

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

#### 2.1.

Если после ответственного чтения данные изменяются, устанавливайте исключительную управляемую блокировку до чтения.
Это снижает риск взаимоблокировок.

#### Пример исключительной блокировки

```bsl
// 1. Установить исключительную блокировку для ответственного чтения
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Приказы");
ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказСсылка);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();

// 2. Получить объект для дальнейшей модификации
Объект = ПриказСсылка.ПолучитьОбъект();
Если Объект = Неопределено Тогда
    Возврат;
КонецЕсли;

// 3. Заблокировать объект от изменения и записать
ЗаблокироватьДанныеДляРедактирования(ПриказСсылка);
Объект.Реквизит = ...;
Объект.Записать();
```

#### 2.2.

Если данные читаются ответственно, но не изменяются (например, только для формирования движений), используйте:

- разделяемую блокировку для читаемых данных;
- исключительную блокировку для данных, которые будут изменяться.

#### Пример разделяемой блокировки

```bsl
// 1. Установить разделяемую блокировку для чтения связанных объектов
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Приказы");
ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказСсылка);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
Блокировка.Заблокировать();

// 2. Прочитать приказ
ПриказОбъект = ПриказСсылка.ПолучитьОбъект();

// 3. Прочитать автора приказа
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Пользователи");
ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказОбъект.Автор);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
Блокировка.Заблокировать();

АвторПриказа = ПриказОбъект.Автор.ПолучитьОбъект();
```

#### См. также

- [#std460: Использование управляемого режима блокировки](https://v8std.ru/std/460/)
- [#std659: Общие сведения об избыточных блокировках](https://v8std.ru/std/659/)
- [#std783: Транзакции: правила использования](https://v8std.ru/std/783/)

#### Проверки

[#acc:1327](https://v8std.ru/diagnostics/acc/1327/)
[#acc:1328](https://v8std.ru/diagnostics/acc/1328/)
#### Источник

https://its.1c.ru/db/v8std#content:648

Отсутствует исключительная управляемая блокировка на записываемые (удаляемые) данные. АПК:1327

Отсутствует разделяемая управляемая блокировка на читаемые данные. АПК:1328

Использование управляемого режима блокировки #std460

Обработчик события ПередЗаписью #std464

Обработчик события ПриЗаписи #std465

Блокировка данных объекта для редактирования из кода #std490

Общие сведения об избыточных блокировках #std659

Обработчик события ПередУдалением #std752

Транзакции: правила использования #std783

Ответственное чтение данных #std648


стандарт 652

ID: #std652

# Несоответствие индексов и условий запроса

#### 1.1.

Проверяйте,
что для всех условий запроса
есть подходящие индексы.

Условия встречаются в секциях:

- `ВЫБРАТЬ ... ИЗ ... ГДЕ `;
- `СОЕДИНЕНИЕ ... ПО `;
- `ВЫБРАТЬ ... ИЗ (, )`;
- `ИМЕЮЩИЕ `.

Подходящий индекс должен:

1. содержать все поля из условия;
2. содержать эти поля в начале индекса;
3. содержать эти поля подряд,
   без «вклинивания» других полей.

#### 1.2.

Если подходящего индекса нет,
СУБД будет сканировать таблицу
или один из ее индексов.
Это увеличивает время выполнения запроса
и может снижать параллельность
из-за роста количества блокировок.

Требования связаны
с физической структурой индекса.
Индекс - это дерево,
где значения полей
идут по уровням:
сначала первое поле,
потом второе и далее.

Быстрый поиск возможен,
когда фильтрация идет
по непрерывному префиксу полей индекса.
Если условия по первому полю нет,
индекс теряет эффективность.
Если между используемыми полями
есть пропуски,
индекс применяется только частично.

#### 2.

При создании объектов метаданных
`1С:Предприятие`
автоматически создает индексы,
которые покрывают большинство запросов.

Основные автоматически создаваемые индексы:

- по уникальному идентификатору (ссылке)
  для объектных сущностей;
- по регистратору
  для таблиц движений регистров,
  подчиненных регистратору;
- по периоду
  и всем измерениям
  для итоговых таблиц регистров накопления;
- по периоду,
  счету
  и всем измерениям
  для итоговых таблиц регистров бухгалтерии.

#### 3.

Если автоматических индексов недостаточно,
можно дополнительно индексировать
реквизиты объектов метаданных.

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

Учитывайте компромисс:
индекс ускоряет поиск,
но может замедлить
добавление,
изменение
и удаление данных.
Индексы добавляйте осознанно,
под конкретные запросы.
Не создавайте индексы
«на всякий случай»
и заведомо избыточные индексы.

В частности:

- не индексируйте дополнительно
  первое измерение регистра:
  для него уже есть основной индекс
  итоговой таблицы,
  автоматически создаваемый платформой;
- не индексируйте низкоселективные поля
  (например,
  реквизит типа `Булево`),
  кроме специальных случаев,
  когда незначительная часть записей
  всегда имеет одно значение,
  и запросы всегда выбирают записи
  именно по нему.

#### Примеры

В конфигурации описан
регистр накопления **ТоварыНаСкладах**:

Изображение: Измерения регистра (652.img1.png)

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

#### Запрос 1: Неправильно

```bsl
Запрос.Текст = "ВЫБРАТЬ
|   ТоварыНаСкладахОстатки.Склад,
|   ТоварыНаСкладахОстатки.Номенклатура,
|   ТоварыНаСкладахОстатки.Качество
|ИЗ
|   РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура = &Номенклатура) КАК ТоварыНаСкладахОстатки";
```

Нарушено требование `2` из п. `1.1`:
в условии нет отбора
по первому полю индекса (`Склад`).
СУБД придется перебирать
весь индекс или таблицу.

Варианты оптимизации:

- проиндексировать измерение **Номенклатура**;
- поставить **Номенклатура** первым измерением
  (осторожно,
  это может замедлить другие запросы).

#### Запрос 2: Неправильно

```bsl
Запрос.Текст = "ВЫБРАТЬ
|   ТоварыНаСкладахОстатки.Склад,
|   ТоварыНаСкладахОстатки.Номенклатура,
|   ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры
|ИЗ
|   РегистрНакопления.ТоварыНаСкладах.Остатки(
|       ,
|       ХарактеристикаНоменклатуры = &ХарактеристикаНоменклатуры
|       И Номенклатура = &Номенклатура
|       И Склад = &Склад) КАК ТоварыНаСкладахОстатки";
```

Нарушено требование `3` из п. `1.1`:
между **Номенклатура**
и **ХарактеристикаНоменклатуры**
в структуре регистра
находится поле **Качество**,
которого нет в условии.

Варианты оптимизации:

- проиндексировать **ХарактеристикаНоменклатуры**;
- поменять местами
  **Качество**
  и **ХарактеристикаНоменклатуры**
  (только если выигрыш критичен,
  так как это может ухудшить
  другие запросы).

#### Запрос 3: Правильно

```bsl
Запрос.Текст = "ВЫБРАТЬ
|   ТоварыНаСкладахОстатки.Склад,
|   ТоварыНаСкладахОстатки.Номенклатура,
|   ТоварыНаСкладахОстатки.Качество,
|   ТоварыНаСкладахОстатки.КоличествоОстаток
|ИЗ
|   РегистрНакопления.ТоварыНаСкладах.Остатки(
|       ,
|       Номенклатура = &Номенклатура
|       И Склад = &Склад) КАК ТоварыНаСкладахОстатки";
```

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

Порядок условий в тексте запроса
не обязан совпадать
с порядком полей в индексе.

#### См. также

- [#metod1590: Индексы таблиц базы данных](https://v8std.ru/metod8dev/1590/)
- [#std658: Эффективные условия запросов](https://v8std.ru/std/658/)

#### Источник

https://its.1c.ru/db/v8std#content:652

1590

Эффективные условия запросов #std658

Несоответствие индексов и условий запроса #std652


стандарт 654

ID: #std654

# Разыменование ссылочных полей составного типа в языке запросов

#### 1.1.

В языке запросов можно обращаться не только к полям таблиц из раздела `ИЗ`, но и к полям объектов, на которые ссылаются ссылочные поля.

Обращение к полям через точку (`ПолеСсылка.Реквизит`) добавляет неявные соединения с дополнительными таблицами.

Это относится и к ограничениям доступа на уровне записей (`RLS`): в запрос могут добавляться таблицы, участвующие в проверках прав к неявно подключенным объектам.

#### Пример

```sdbl
ВЫБРАТЬ
    ТоварныеЗапасы.Товар КАК Товар,
    ТоварныеЗапасы.Количество КАК Количество,
    ТоварныеЗапасы.Товар.Артикул КАК Артикул
ИЗ
    РегистрНакопления.ТоварныеЗапасы КАК ТоварныеЗапасы
```

#### 1.2.

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

Особенно это критично для ссылочных полей [#std728: составного типа](https://v8std.ru/std/728/): платформа может соединять запрос со всеми таблицами, которые входят в состав типа, а также с таблицами из `RLS` этих объектов

#### Неправильно

```sdbl
ВЫБРАТЬ
    ТоварныеЗапасы.Регистратор.Дата КАК ДатаРегистратора
ИЗ
    РегистрНакопления.ТоварныеЗапасы КАК ТоварныеЗапасы
```

Подобное получение данных через точку от ссылочных полей составного типа крайне нежелательно.
Каждое исключение из этого правила нужно отдельно анализировать.

#### 2.1.

Избегайте избыточных составных типов ссылочных полей.

Указывайте только те типы ссылок, которые действительно нужны бизнес-логике.
Без необходимости не применяйте варианты вида «любая ссылка».

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

#### 2.2.

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

Например, можно добавить в регистр реквизит `ДатаРегистратора`, заполнять его при проведении и использовать в запросах напрямую.

#### Правильно

```sdbl
ВЫБРАТЬ
    ТоварныеЗапасы.ДатаРегистратора
ИЗ
    РегистрНакопления.ТоварныеЗапасы КАК ТоварныеЗапасы
```

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

#### 2.3.

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

- Для конкретного запроса обычно не нужны все возможные типы составной ссылки. Ограничивайте их через `ВЫРАЗИТЬ`.
- Если один и тот же запрос используется в разных сценариях, формируйте его текст динамически и подставляйте в `ВЫРАЗИТЬ` нужный тип в зависимости от контекста.

Это увеличит объем кода и может снизить универсальность, но обычно заметно повышает производительность и стабильность.

#### Неправильно

```sdbl
ВЫБРАТЬ
    Продажи.Регистратор.Номер КАК Номер,
    Продажи.Регистратор.Дата КАК Дата,
    Продажи.Контрагент КАК Контрагент,
    Продажи.Количество КАК Количество,
    Продажи.Стоимость КАК Стоимость
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    ...
```

В этом примере поле `Регистратор` может быть ссылкой на один из десятков типов документов.
В таком случае SQL-текст развернется в большое число соединений (в исходном стандарте показан пример с `56` соединениями), что резко ухудшает производительность.

#### Правильно

```sdbl
ВЫБРАТЬ
    ВЫБОР
        КОГДА Продажи.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
            ТОГДА ВЫРАЗИТЬ(Продажи.Регистратор КАК Документ.РеализацияТоваровУслуг).Номер
        КОГДА Продажи.Регистратор ССЫЛКА Документ.ЗаказПокупателя
            ТОГДА ВЫРАЗИТЬ(Продажи.Регистратор КАК Документ.ЗаказПокупателя).Номер
    КОНЕЦ КАК Номер,
    ВЫБОР
        КОГДА Продажи.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
            ТОГДА ВЫРАЗИТЬ(Продажи.Регистратор КАК Документ.РеализацияТоваровУслуг).Дата
        КОГДА Продажи.Регистратор ССЫЛКА Документ.ЗаказПокупателя
            ТОГДА ВЫРАЗИТЬ(Продажи.Регистратор КАК Документ.ЗаказПокупателя).Дата
    КОНЕЦ КАК Дата,
    Продажи.Контрагент КАК Контрагент,
    Продажи.Количество КАК Количество,
    Продажи.Стоимость КАК Стоимость
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    Продажи.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
    ИЛИ Продажи.Регистратор ССЫЛКА Документ.ЗаказПокупателя
```

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

#### См. также

- [#std477: Самодостаточность регистров](https://v8std.ru/std/477/)
- [#std437: Оформление текстов запросов](https://v8std.ru/std/437/)
- [#std657: Обращения к виртуальным таблицам](https://v8std.ru/std/657/)
- [#std658: Эффективные условия запросов](https://v8std.ru/std/658/)
- [#std728: Ограничения на использование реквизитов составного типа](https://v8std.ru/std/728/)

#### Проверки

[#acc:1377](https://v8std.ru/diagnostics/acc/1377/)
#### Источник

https://its.1c.ru/db/v8std#content:654

В языке запросов можно обращаться не только к полям таблиц из раздела ИЗ, но и к полям объектов, на которые ссылаются ссылочные поля.

Разыменование ссылочного поля составного типа АПК:1377

Оформление текстов запросов #std437

Самодостаточность регистров #std477

Обращения к виртуальным таблицам #std657

Эффективные условия запросов #std658

Ограничения на использование реквизитов составного типа #std728

Разыменование ссылочных полей составного типа в языке запросов #std654


стандарт 655

ID: #std655

# Ограничения на соединения с вложенными запросами и виртуальными таблицами

#### 1.1.

В запросах не используйте соединения с вложенными запросами.
Соединяйте только объекты метаданных или временные таблицы.

Если в запросе есть соединение с вложенным запросом, переписывайте его с [#std777: использованием временных таблиц](https://v8std.ru/std/777/)
Это правило действует независимо от того, с какой стороны соединения находится вложенный запрос.

Исключение: вложенный запрос гарантированно сканирует мало записей.

Соединение с вложенным запросом может привести к проблемам:

- крайне медленное выполнение даже при слабой загрузке сервера (вплоть до замедления на несколько порядков);
- нестабильная скорость (в одних условиях быстро, в других - очень медленно);
- существенная разница времени выполнения на разных СУБД;
- чувствительность к актуальности и полноте статистик (после обновления статистик быстро, затем снова медленно).

#### Потенциально опасный запрос

```sdbl
ВЫБРАТЬ ...
ИЗ Документ.РеализацияТоваровУслуг
ЛЕВОЕ СОЕДИНЕНИЕ (
    ВЫБРАТЬ ИЗ РегистрСведений.Лимиты
    ГДЕ ...
    СГРУППИРОВАТЬ ПО ...
) ПО ...
```

#### Уточнение

Оптимизатор СУБД (независимо от конкретной СУБД) не всегда корректно оптимизирует такие запросы.
Ключевая сложность - выбор способа соединения.

Для соединения выборок существует несколько алгоритмов.
Правильный выбор зависит от того, сколько строк ожидается в каждой выборке.

Если соединяются две физические таблицы, СУБД обычно может оценить их объем по статистике.
Если одна из выборок - вложенный запрос, оценка его объема становится намного менее точной.
Из-за этого СУБД может выбрать неверный план, что приводит к резкому падению производительности.

#### 1.2.

Для ситуации из п. `1.1` используйте пакетный запрос и временную таблицу:

#### Правильно

```bsl
// Создать менеджер временных таблиц
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

// Текст пакетного запроса
Запрос.Текст = "
|   // Заполняем временную таблицу. Запрос к регистру лимитов.
|   ВЫБРАТЬ ...
|   ПОМЕСТИТЬ Лимиты
|   ИЗ РегистрСведений.Лимиты
|   ГДЕ ...
|   СГРУППИРОВАТЬ ПО ...
|   ИНДЕКСИРОВАТЬ ПО ...;
|
|   // Выполняем основной запрос с использованием временной таблицы
|   ВЫБРАТЬ ...
|   ИЗ Документ.РеализацияТоваровУслуг
|   ЛЕВОЕ СОЕДИНЕНИЕ Лимиты
|   ПО ...;";
```

Такой подход:

- упрощает работу оптимизатора (в соединении участвуют физические таблицы с понятным объемом);
- повышает стабильность плана выполнения;
- дает более предсказуемую производительность на разных СУБД;
- улучшает читаемость и упрощает отладку запроса.

#### 2.

Если запрос соединяется с виртуальной таблицей языка запросов `1С:Предприятия`
(например, `РегистрНакопления.Товары.Остатки`)
и работает медленно, вынесите обращение к виртуальной таблице
в отдельный запрос с сохранением результата во временную таблицу
(см. п. `1.1`).

#### 3.

Избегайте неявных подзапросов, которые появляются из-за вложенных соединений.

#### Неправильно

```sdbl
ВЫБРАТЬ ...
ИЗ Справочник.Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыОрганизаций
        ПО ...
    ПО ...
```

По сути это эквивалентно соединению с подзапросом:

```sdbl
ВЫБРАТЬ ...
ИЗ Справочник.Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ (
        ВЫБРАТЬ ...
        ИЗ РегистрНакопления.ТоварыНаСкладах
            ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыОрганизаций
            ПО ...)
    ПО ...
```

Используйте последовательные соединения:

#### Правильно

```sdbl
ВЫБРАТЬ ...
ИЗ Справочник.Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах
        ПО ...
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыОрганизаций
        ПО ...
```

Важно: вложенные и последовательные соединения - разные запросы, они могут давать разный результат.

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

#### См. также

- [#std656: Ограничения на использование вложенных запросов в условии соединения](https://v8std.ru/std/656/)
- [#std777: Использование временных таблиц](https://v8std.ru/std/777/)

#### Проверки
[#bslls:JoinWithSubQuery](https://v8std.ru/diagnostics/bslls/JoinWithSubQuery/)
[#bslls:JoinWithVirtualTable](https://v8std.ru/diagnostics/bslls/JoinWithVirtualTable/)

[#acc:494](https://v8std.ru/diagnostics/acc/494/)
#### Источник

https://its.1c.ru/db/v8std#content:655

Использование запроса, выполняющего соединение с вложенным запросом. АПК:494

Соединение с вложенными запросами BSLLS:JoinWithSubQuery

Соединение с виртуальными таблицами BSLLS:JoinWithVirtualTable

Ограничения на использование вложенных запросов в условии соединения #std656

Использование временных таблиц #std777

Ограничения на соединения с вложенными запросами и виртуальными таблицами #std655


стандарт 656

ID: #std656

# Ограничения на использование вложенных запросов в условии соединения

Не используйте вложенные запросы в условии соединения.
Это может существенно замедлить запрос и в ряде случаев сделать его неработоспособным на отдельных СУБД.

Типовой проблемный сценарий:
в условии соединения используется вложенный запрос,
чтобы получить «срез последних» на конец предыдущего периода,
причем для каждой номенклатуры период может отличаться.

#### Неправильно

```sdbl
ВЫБРАТЬ
    ОстаткиТоваров.Номенклатура КАК Номенклатура,
    Цены.Цена КАК ЦенаПрошлогоМесяца
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(...) КАК ОстаткиТоваров
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цена КАК Цены
    ПО Цены.Номенклатура = ОстаткиТоваров.Номенклатура
       И Цены.Период В (
            ВЫБРАТЬ МАКСИМУМ(ЦеныПрошлогоМесяца.Период)
            ИЗ РегистрСведений.Цена КАК ЦеныПрошлогоМесяца
            ГДЕ ЦеныПрошлогоМесяца.Период < НАЧАЛОПЕРИОДА(ОстаткиТоваров.Период, МЕСЯЦ)
                И ЦеныПрошлогоМесяца.Номенклатура = ОстаткиТоваров.Номенклатура
       )
ГДЕ
    ОстаткиТоваров.Склад = &Склад
```

#### Правильно

```sdbl
// Максимальные даты установки цен в прошлом периоде для данных номенклатур
ВЫБРАТЬ
    ОстаткиТоваров.Номенклатура КАК Номенклатура,
    МАКСИМУМ(Цены.Период) КАК Период
ПОМЕСТИТЬ ДатыПоНоменклатурам
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(..., Склад = &Склад) КАК ОстаткиТоваров
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цена КАК Цены
        ПО Цены.Номенклатура = ОстаткиТоваров.Номенклатура
           И Цены.Период < НАЧАЛОПЕРИОДА(ОстаткиТоваров.Период, МЕСЯЦ)
СГРУППИРОВАТЬ ПО
    ОстаткиТоваров.Номенклатура
;

// Выбрать данные по цене за найденный период
ВЫБРАТЬ
    ДатыПоНоменклатурам.Номенклатура КАК Номенклатура,
    Цены.Цена КАК ЦенаПрошлогоМесяца
ИЗ
    ДатыПоНоменклатурам
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цена КАК Цены
        ПО Цены.Номенклатура = ДатыПоНоменклатурам.Номенклатура
           И Цены.Период = ДатыПоНоменклатурам.Период
```

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

#### См. также

- [#std655: Ограничения на соединения с вложенными запросами и виртуальными таблицами](https://v8std.ru/std/655/)
- [#std777: Использование временных таблиц](https://v8std.ru/std/777/)

#### Источник

https://its.1c.ru/db/v8std#content:656

Использование временных таблиц #std777


стандарт 657

ID: #std657

# Обращения к виртуальным таблицам

#### 1.

Передавайте в параметры виртуальной таблицы все условия, относящиеся к ней. Не переносите такие условия в секцию `ГДЕ`.

Так запрос будет работать быстрее: СУБД сможет выбрать лучший план выполнения и не будет обрабатывать лишние записи.

#### Неправильно

```sdbl
ВЫБРАТЬ
    Номенклатура
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки()
ГДЕ
    Склад = &Склад
```

#### Правильно

```sdbl
ВЫБРАТЬ
    Номенклатура
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад)
```

#### 2.1.

В параметрах виртуальной таблицы используйте простые условия вида `Измерение = Значение`. Не используйте подзапросы и соединения.

#### Примечание

Под соединениями понимаются:

- явные соединения в подзапросах;
- неявные соединения при обращении к полям через точку;
- соединения, добавляемые из ограничений доступа к данным (RLS).

#### 2.2.

Если подзапросы нужны, соблюдайте условия:

- в подзапросе только одна таблица, без соединений с другими таблицами;
- если таблица подзапроса - табличная часть, не обращайтесь к реквизитам шапки документа;
- если таблица подзапроса - документ с табличными частями, не обращайтесь к табличным частям;
- если таблица подзапроса - временная, не используйте раздел `ГДЕ`;
- если таблица подзапроса - постоянная, раздел `ГДЕ` допустим только если условие выполняется в 80% случаев и более;
- если таблица подзапроса - постоянная, в RLS не должно быть подзапросов и соединений (допустимы только простые условия).

#### Неправильно

```sdbl
...
ИЗ
РегистрНакопления.ТоварыКОтгрузке.Остатки(
    &ДатаОтгрузки,
    &ОтображениеРаспоряжений
    И ДокументОтгрузки.Склад = &Склад // (1)
    ИЛИ ДокументОтгрузки В
        (ВЫБРАТЬ // (2)
            Распоряжения.Распоряжение КАК ДокументОтгрузки
        ИЗ
            Документ.ЗаданиеНаПеревозку.Распоряжения КАК Распоряжения // (3)
            ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаданиеНаПеревозку.СкладыПогрузки КАК СкладыПогрузки
        ПО
            Распоряжения.Ссылка = СкладыПогрузки.Ссылка
            И СкладыПогрузки.Склад = &Склад
            И Распоряжения.Ссылка.Проведен // (4)
            И Распоряжения.Ссылка.Статус В (...)))
```

1. Неявное соединение через точку
2. Подзапрос с соединением
3. Доступ к этому документу ограничен по сложному RLS, который неявно добавляет еще пару соединений
4. Здесь и ниже обращения к реквизитам шапки

#### Правильно

```sdbl
...
ИЗ
РегистрНакопления.ТоварыКОтгрузке.Остатки(
    &ДатаОтгрузки,
    Склад = &Склад // (1)
    ИЛИ ДокументОтгрузки В
        (ВЫБРАТЬ
            ЗаданияНаПеревозку.Распоряжение
        ИЗ
            ВременнаяТаблицаЗаданийНаПеревозку КАК ЗаданияНаПеревозку)) // (2)
```

1. Теперь это реквизит регистра
2. Выборка из временной таблицы без условий

#### 2.3.

Если нужно несколько условий с подзапросами, выберите одно, которое удовлетворяет требованиям выше и отфильтровывает максимум записей. Остальные условия накладывайте на внешний запрос.

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

#### Неправильно

```sdbl
Номенклатура В (...)
И Характеристика В (...)
И Серия В (...)
```

#### Правильно

```sdbl
(Номенклатура, Характеристика, Серия) В
    (ВЫБРАТЬ
        Номенклатура,
        Характеристика,
        Серия
    ИЗ
        ВременнаяТаблицаТоваров)
```

#### См. также

- [#std654: Разыменование ссылочных полей составного типа в языке запросов](https://v8std.ru/std/654/)
- [#std733: Эффективное обращение к виртуальной таблице "Остатки"](https://v8std.ru/std/733/)
- [Использование параметра Условие при обращении к виртуальной таблице (статья на ИТС)](https://its.1c.ru/db/metod8dev#content:5457:hdoc)

#### Проверки
[#bslls:VirtualTableCallWithoutParameters](https://v8std.ru/diagnostics/bslls/VirtualTableCallWithoutParameters/)
[#v8cs:ql-virtual-table-filters](https://v8std.ru/diagnostics/v8-code-style/ql-virtual-table-filters/)

#### Источник

https://its.1c.ru/db/v8std#content:657

Передавайте в параметры виртуальной таблицы все условия, относящиеся к ней. Не переносите такие условия в секцию ГДЕ.

Обращение к виртуальной таблице без параметров BSLLS:VirtualTableCallWithoutParameters

Отбор виртуальной таблицы должен быть в параметрах (ql-virtual-table-filters)

Эффективное обращение к виртуальной таблице «Остатки» #std733


стандарт 658

ID: #std658

# Эффективные условия запросов

#### 1.

Условия запросов пишите с учетом производительности.
Цель: не допускать существенного роста времени выполнения при увеличении объема данных.

Поля основного условия в секциях `ГДЕ`, `ПО` и в параметрах виртуальных таблиц должны быть проиндексированы.
Основное условие можно уточнять дополнительным условием, но объединять их нужно через `И`.

Важно учитывать структуру индексов:

- для разных полей метаданных создаются разные индексы;
- в одном запросе обычно используется только один индекс в основном условии;
- основное условие лучше строить на автоматически создаваемых платформой индексах.

**Основное условие** — это условие, которое сильнее всего сокращает выборку.
Его составляющие объединяются по `И`.

**Дополнительное условие** — это уточнение основного условия.
Оно тоже объединяется с основным по `И`, но внутри может быть сложным:
`НЕ`, `<>`, арифметика, функции и т.п.

В основном условии используйте только операции, которые позволяют поиск по индексу:

- для первого и всех используемых полей индекса, кроме последнего: только `=` и `И`;
- для последнего (или единственного) используемого поля индекса допустимы: `=`, `>`, `=`, `<=`, `ПОДОБНО`, `МЕЖДУ`, `В`, `ИЛИ` (если приводится к `В`);
- нельзя использовать арифметику, функции, отрицания и неравенства в основном условии.

Для индексации ориентируйтесь на место условия:

- условия в `ГДЕ` и параметрах виртуальной таблицы: индексируйте поля основной таблицы выборки;
- условия в `ПО` левого соединения: индексируйте поля правой таблицы;
- условия в `ПО` внутреннего соединения: индексируйте поля таблицы с большим числом записей.

См. также:

- [Индексы таблиц базы данных](https://its.1c.ru/db/metod8dev#content:1590:hdoc)
- [#std652: Несоответствие индексов и условий запроса](https://its.1c.ru/db/v8std#content:652)

#### 1.1.

Требования раздела `1` можно не применять, если:

- в таблицах всегда мало данных (менее `1000` записей);
- запросы с такими условиями выполняются редко.

#### 1.2.

Если записей много и требования раздела `1` выполнить невозможно:

- преобразуйте условия (см. разделы [3](https://v8std.ru/std/658/#3) и [4](https://v8std.ru/std/658/#4))
- добавьте заранее вычисляемые индексируемые поля и заполняйте их при записи;
- если это не помогло, пересмотрите архитектуру решения.

#### 2.

Оператор `ИЛИ`.

#### 2.1.

В основном условии `ИЛИ` допустим только для последнего (или единственного) поля индекса,
когда выражение можно привести к `В`.

#### Правильно

```sdbl
ГДЕ
    Таблица.Поле = &Значение1
    ИЛИ Таблица.Поле = &Значение2
```

#### Правильно / Эквивалентно (переписывать необязательно):

```sdbl
ГДЕ
    Таблица.Поле В (&Значения)
```

#### Неправильно

```sdbl
ГДЕ
    Таблица.Поле1 = &Значение1
    ИЛИ Таблица.Поле2 = &Значение2
```

Такое выражение к `В` не приводится.
В ряде случаев его можно заменить на `ОБЪЕДИНИТЬ ВСЕ` (если это сохраняет семантику):

```sdbl
... ГДЕ
    Таблица.Поле1 = &Значение1

ОБЪЕДИНИТЬ ВСЕ

... ГДЕ
    Таблица.Поле2 = &Значение2
```

#### Примечание

Замена `ИЛИ` на `ОБЪЕДИНИТЬ ВСЕ` применима не всегда.
Перед заменой проверьте, что результат выборки не изменится.

#### 2.2.

В дополнительном условии оператор `ИЛИ` можно использовать без ограничений.

#### Правильно

```sdbl
ГДЕ
    Таблица.Поле1 = &Значение1 // Основное условие (индекс)
    И
    (Таблица.Поле2 = &Значение2 ИЛИ Таблица.Поле3 = &Значение3) // Дополнительное условие
```

#### Правильно

```sdbl
ГДЕ
    (Таблица.Поле1 = &Значение1 ИЛИ Таблица.Поле1 = &Значение2)
    И
    (Таблица.Поле2 = &Значение3 ИЛИ Таблица.Поле2 = &Значение4)
```

#### Правильно / Эквивалентно (переписывать необязательно):

```sdbl
ГДЕ
    Таблица.Поле1 В (&Значения1) // Основное условие
    И Таблица.Поле2 В (&Значения2) // Дополнительное условие
```

#### 3.

Оператор `ПОДОБНО`.

В основном условии `ПОДОБНО` можно применять для последнего
(или единственного) используемого поля индекса.

Функции обработки строк по возможности приводите к `ПОДОБНО`.

#### Неправильно

```sdbl
ГДЕ
    ПОДСТРОКА(Таблица.Поле, 1, 6) = "строка"
```

#### Правильно

```sdbl
ГДЕ
    Таблица.Поле ПОДОБНО "строка%"
```

#### Неправильно

```sdbl
ГДЕ
    ПОДСТРОКА(Таблица.Поле, 3, 6) = "строка"
```

#### Неправильно

```sdbl
ГДЕ
    Таблица.Поле ПОДОБНО "__строка%"
```

Литерал не должен начинаться с `_` или `%`.

#### Правильно

Добавьте вычисляемое при записи поле, например с фрагментом
`ПОДСТРОКА(Таблица.Поле, 3, 6)`, проиндексируйте его и ищите по нему:

```sdbl
ГДЕ
    Таблица.ВычисляемоеПоле ПОДОБНО "строка%"
```

#### 4.

Оператор `МЕЖДУ`.

В основном условии `МЕЖДУ` можно использовать для последнего
(или единственного) поля индекса.

Функции работы с датами по возможности приводите к `МЕЖДУ`.

#### Неправильно

```sdbl
ГДЕ
    МЕСЯЦ(Таблица.Поле) = 1
```

#### Правильно

```sdbl
ГДЕ
    Таблица.Поле МЕЖДУ &ДатаНачалаМесяца И &ДатаКонцаМесяца
```

Пример границ:

- `ДатаНачалаМесяца = 01.01.2016`;
- `ДатаКонцаМесяца = 31.01.2016 23:59:59`.

#### 5.

Выражение `ВЫБОР` используйте только в дополнительных условиях.

#### Правильно

```sdbl
ГДЕ
    Таблица.Поле1 = &Значение1 // Основное условие (индекс)
    И
    ВЫБОР
        КОГДА Таблица.Поле2 = &Значение2
            ТОГДА Таблица.Поле3 = &Значение3
        ИНАЧЕ Таблица.Поле4 = &Значение4
    КОНЕЦ
```

#### Неправильно

```sdbl
ГДЕ
    ВЫБОР // Основное условие (индекс использоваться не будет)
        КОГДА Таблица.Поле2 = &Значение2
            ТОГДА Таблица.Поле3 = &Значение3
        ИНАЧЕ Таблица.Поле4 = &Значение4
    КОНЕЦ
```

#### 6.

Арифметические операции над полями выполняйте только в дополнительных условиях.

#### Правильно

```sdbl
ГДЕ
    Таблица.Поле1 = &Значение1 // Основное условие (индекс)
    И Таблица.Поле2 - 1 > 0 // Дополнительное условие
```

#### Неправильно

```sdbl
ГДЕ
    Таблица.Поле1 - 1 > 0 // Основное условие (поиск по индексу невозможен)
```

#### 7.

Если для одного объекта и одного права пользователю назначены несколько ролей
с разными условиями `RLS`, итоговый запрос к СУБД получит объединение условий через `ИЛИ`.

Это может ухудшить производительность и увеличить блокировки,
даже если в исходном тексте запроса оператора `ИЛИ` не было.

Чтобы этого избежать:

- проектируйте роли так, чтобы доступ к объекту для конкретного права давала одна роль;
- если ролей несколько, задавайте одинаковые условия `RLS` для одного и того же права объекта.

#### См. также

- [Типичные причины неоптимальной работы запросов и методы оптимизации](https://its.1c.ru/db/metod8dev#content:5842:hdoc)
- [#std488: Стандартные роли](https://v8std.ru/std/488/)
- [#std689: Настройка ролей и прав доступа](https://v8std.ru/std/689/)

#### Проверки
[#v8cs:ql-constants-in-binary-operation](https://v8std.ru/diagnostics/v8-code-style/ql-constants-in-binary-operation/)

#### Источник

https://its.1c.ru/db/v8std#content:658

В запросе в бинарной операции используются константные значения или параметры. (ql-constants-in-binary-operation)

Стандартные роли #std488

Настройка ролей и прав доступа #std689

Эффективные условия запросов #std658


стандарт 659

ID: #std659

# Общие сведения об избыточных блокировках

#### 1.

Ошибки в проектировании структуры объектов метаданных могут привести к большому количеству избыточных блокировок и заметному падению производительности системы.

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

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

При анализе структуры метаданных в первую очередь проверяйте:

- последовательности;
- регистры бухгалтерии;
- регистры накопления.

#### См. также

- [#std661: Блокирующее чтение остатков в начале транзакции](https://v8std.ru/std/661/)
- [#std460: Использование управляемого режима блокировки](https://v8std.ru/std/460/)
- [#std652: Несоответствие индексов и условий запроса](https://v8std.ru/std/652/)
- [#std654: Разыменование ссылочных полей составного типа в языке запросов](https://v8std.ru/std/654/)
- [#std655: Ограничения на соединения с вложенными запросами и виртуальными таблицами](https://v8std.ru/std/655/)
- [#std656: Ограничения на использование вложенных запросов в условии соединения](https://v8std.ru/std/656/)
- [#std657: Обращения к виртуальным таблицам](https://v8std.ru/std/657/)
- [#std658: Эффективные условия запросов](https://v8std.ru/std/658/)

#### Источник

https://its.1c.ru/db/v8std#content:659

Использование управляемого режима блокировки #std460

Эффективные условия запросов #std658

Блокирующее чтение остатков в начале транзакции #std661

Общие сведения об избыточных блокировках #std659


стандарт 661

ID: #std661

# Блокирующее чтение остатков в начале транзакции

#### 1.1.

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

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

#### 1.2.

Чтение остатков в этом сценарии должно быть блокирующим.
Нужно запретить двум пользователям одновременно читать один и тот же остаток
за период, счет и значения измерений.

Если чтение неблокирующее, два пользователя могут одновременно прочитать один и тот же остаток
и независимо принять решение о списании.

Пример: оба пользователя видят `10` единиц остатка.
Первый списывает `8`, второй списывает `6`.
Итоговый остаток становится `-4`, что недопустимо для прикладной логики.

#### 2.

Обычно контроль остатков делают запросом в модуле набора записей перед записью набора.
У такого подхода есть две проблемы:

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

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

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

- заранее анализируйте, какие остатки нужно контролировать и в каких случаях;
- учитывайте сценарии, где контроль не нужен:
  - приходный документ может только увеличить остатки;
  - при перепроведении документ может списывать не больше, чем списал при первом проведении;
- в начале транзакции (например, в `ОбработкаПроведения`) явно записывайте движения по регистрам, где контроль не нужен;
- всегда используйте одинаковый порядок записи регистров (например, алфавитный);
- для этих наборов записей ставьте `БлокироватьДляИзменения = Ложь`;
- убедитесь, что у всех записываемых регистров накопления и бухгалтерии включен режим разделения итогов;
- выполните остальную логику транзакции;
- в самом конце транзакции явно запишите движения по регистрам, где контроль нужен;
- для наборов записей этих регистров ставьте `БлокироватьДляИзменения = Истина` (это снижает риск взаимоблокировок);
- после записи выполняйте запросы контроля остатков по отрицательным остаткам для нужного набора измерений;
- если отрицательные остатки найдены, отменяйте транзакцию; если запрос пустой, фиксируйте.

Явную управляемую блокировку (`ДЛЯ ИЗМЕНЕНИЯ` в автоматическом режиме)
в этом месте обычно не используют, потому что нужные остатки уже заблокированы записью на предыдущем шаге.

#### Пример

В процедуре `ПередЗаписью` модуля набора записей регистра бухгалтерии `Хозрасчетный`
выполняется запрос:

#### Пример запроса

```bsl
Запрос.Текст = "ВЫБРАТЬ
  |   СуммаОстаток,
  |   СуммаОстатокДт,
  |   СуммаОстатокКт
  |ИЗ
  |   РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, &Счет, , Организация = &Организация)";
```

Такой запрос читает и блокирует остатки по условию для всех пользовательских подключений.
Ресурсы, созданные разделением итогов, фактически объединяются в один.
В результате параллельность становится такой же, как если бы разделение итогов было отключено.

Чтобы снизить влияние этой блокировки, переносите проверку как можно ближе к концу транзакции.
Например, в модуль документа, в `ПриПроведении`, после явной записи всех движений по всем регистрам.

#### См. также

- [#std648: Ответственное чтение данных](https://v8std.ru/std/648/)
- [#std663: Режим разделения итогов для регистров бухгалтерии](https://v8std.ru/std/663/)

#### Источник

https://its.1c.ru/db/v8std#content:661

Ответственное чтение данных #std648

Режим разделения итогов для регистров бухгалтерии #std663


стандарт 662

ID: #std662

# Сдвиг границы последовательности документов

#### 1.

Не рекомендуется сдвигать границу последовательности при проведении документов.
Это может вызывать ожидания на блокировках и снижать общую производительность системы.

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

Граница последовательности по одному набору значений измерений - это один ресурс.
Если несколько пользователей одновременно сдвигают границу по одному и тому же набору значений, они блокируют друг друга.

#### Пример

В системе на базе `УПП 1.x` может использоваться учетная политика
с оперативным расчетом себестоимости списания (в момент проведения документа).

#### Пример настройки в УПП

Изображение: Флажок оперативного расчета себестоимости в УПП (662.upp-operational-costing.png)

Алгоритмы партионного учета в `УПП 1.x` используют последовательность `Партионный учет`
с одним измерением `Организация`.

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

Если два пользователя одновременно проводят расходные документы по одной организации,
они будут блокировать друг друга.

Это не особенность механизма последовательностей `1С:Предприятия`,
а следствие требований самого алгоритма:
конкурирующие по времени документы должны выстроиться в строгом порядке.

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

#### См. также

- [#std659: Общие сведения об избыточных блокировках](https://v8std.ru/std/659/)

#### Источник

https://its.1c.ru/db/v8std#content:662

Сдвиг границы последовательности документов #std662


стандарт 663

ID: #std663

# Режим разделения итогов для регистров бухгалтерии

#### 1.

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

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

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

Если одновременно выполняется контроль остатков, ориентируйтесь на рекомендации [#std661: блокирующего чтения остатков](https://v8std.ru/std/661/)

#### Пример 1

В конфигурации есть регистр `Хозрасчетный` с измерениями `Организация` и `Валюта`.

#### Регистр без разделения итогов

Изображение: Регистр бухгалтерии без разделения итогов (663.mode-disabled-reg.png)

Изображение: Настройки регистра без разделения итогов (663.example-no-split.png)

Если два пользователя одновременно проводят документы, они блокируют друг друга, когда движения:

- относятся к одному периоду;
- относятся к одному счету;
- имеют одинаковые значения измерений (организация и валюта).

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

#### Пример 2

Для того же регистра включите разделение итогов.

#### Включение разделения итогов

Изображение: Разрешение разделения итогов в конфигураторе (663.mode-enabled-config.png)

Изображение: Включение разделения итогов в режиме 1С:Предприятие (663.mode-enabled-runtime.png)

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

Если при этом выполняется контроль остатков, эффект от разделения итогов ограничен.

#### См. также

- [#std661: Блокирующее чтение остатков в начале транзакции](https://v8std.ru/std/661/)
- [Устройство и использование режима разделения итогов регистров (статья на ИТС)](https://its.1c.ru/db/metod81/content/1393/hdoc)
- [#std733: Эффективное обращение к виртуальной таблице «Остатки»](https://v8std.ru/std/733/)

#### Источник

https://its.1c.ru/db/v8std#content:663


стандарт 664

ID: #std664

# Режим разделения итогов для регистров накопления

#### 1.

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

Из-за этого реальная степень параллельности зависит от состава измерений.
Состав измерений нужно подбирать под прикладную задачу и требуемую «гранулярность» остатков.

#### 2.

Если текущий состав измерений не дает нужной параллельности, используйте разделение итогов (по аналогии с [#std663: регистрами бухгалтерии](https://v8std.ru/std/663/))

Разделение итогов не дает нужного эффекта в части контроля остатков.
Если контроль обязателен, переносите его как можно ближе к концу транзакции (см. [#std661: блокирующее чтение остатков](https://v8std.ru/std/661/))

Рассмотрим регистр `ТоварыНаСкладах`.

#### Состав измерений

Изображение: Состав измерений регистра накопления (664.register-measurements.png)

#### Пример 1

Два пользователя одновременно записывают движения в регистр.
Первый пользователь записывает:

| № | Склад           | Номенклатура                 |
| - | --------------- | ---------------------------- |
| 1 | Основной склад  | Кресло-качалка              |
| 2 | Основной склад  | Кухонный гарнитур "Тинга-2" |
| 3 | Склад №2        | Мебельный гарнитур "Торэ"   |

Второй пользователь записывает:

| № | Склад          | Номенклатура               |
| - | -------------- | -------------------------- |
| 1 | Основной склад | Мебельный гарнитур "Торэ" |
| 2 | Склад №2       | Кресло-качалка            |

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

#### Пример 2

Теперь второй пользователь записывает:

| № | Склад          | Номенклатура                 |
| - | -------------- | ---------------------------- |
| 1 | Основной склад | Кухонный гарнитур "Тинга-2" |
| 2 | Склад №2       | Кресло-качалка              |
| 3 | Оптовый склад  | Спальный гарнитур "Инга-М"  |

Этот набор содержит строку, совпадающую по всем измерениям со строкой первого пользователя.
В результате возникает ожидание блокировки, и один пользователь ждет завершения операции другого.

#### Пример 3

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

Но при включенном контроле остатков разделение итогов не даст ожидаемого прироста, и контроль остатков нужно переносить к концу транзакции.

#### См. также

- [#std663: Режим разделения итогов для регистров бухгалтерии](https://v8std.ru/std/663/)
- [#std661: Блокирующее чтение остатков в начале транзакции](https://v8std.ru/std/661/)
- [Устройство и использование режима разделения итогов регистров (статья на ИТС)](https://its.1c.ru/db/metod81/content/1393/hdoc)
- [#std733: Эффективное обращение к виртуальной таблице «Остатки»](https://v8std.ru/std/733/)

#### Источник

https://its.1c.ru/db/v8std#content:664

Режим разделения итогов для регистров накопления #std664


стандарт 668

ID: #std668

# Разработка ролей в библиотеках

#### 1.

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

- в библиотеку включайте объекты метаданных, которые в неизменном или переопределенном виде войдут в конфигурации-потребители;
- объекты, специфичные для конкретной конфигурации-потребителя, не разрабатывайте в библиотеке, а создавайте на этапе внедрения и настройки.

#### 2.

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

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

Исключения:

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

#### 3.

В ролях допустимо задавать не только права к объектам, но и ограничения доступа на уровне записей (RLS).

Поставляемый RLS разрабатывайте так, чтобы его можно было использовать «как есть» без доработки в прикладном решении.
Тогда библиотечные роли можно переносить при обновлении без изменений.

Исключения:

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

#### 4.

Если для библиотечных ролей используются правила поставки, для всех ролей задавайте правило `Изменения разрешены`.

Это связано с особенностями платформы: при добавлении или удалении метаданных роли изменяются неявно.

#### См. также

- [#std488: Стандартные роли](https://v8std.ru/std/488/)
- [#std553: Переопределяемые и поставляемые объекты библиотеки](https://v8std.ru/std/553/)
- [#std689: Настройка ролей и прав доступа](https://v8std.ru/std/689/)

#### Источник

https://its.1c.ru/db/v8std#content:668

Стандартные роли #std488

Переопределяемые и поставляемые объекты библиотеки #std553

Настройка ролей и прав доступа #std689

Разработка ролей в библиотеках #std668


стандарт 669

ID: #std669

# Ограничение на выполнение внешнего кода

Внешний код может быть подключен с помощью:

- внешних отчетов
- внешних обработок
- расширений конфигурации
- внешних компонент
- другими способами (какими?)

Внешний код может содержать деструктивные действия:

- в самом коде выполнить действие
- запустить внешнее приложение
- внешнюю компоненту
- создать COM-объект

Пример уязвимости [Информация для пользователей и партнеров №21537 от 22.06.2016](https://1c.ru/news/info.jsp?id=21537)

#### 1.
Запрещено выполнение на сервере в небезопасном режиме любого кода, который не является частью программы.

Запускать можно код, прошедший аудит.
Или код на клиенте.

#### Например

- внешние отчеты и обработки, расширения, внешние компоненты, любые аналоги подключения внешнего кода
- алгоритмы на встроенном языке, тексты запросов и фрагменты текстов запросов, используемые в методах `Выполнить` и `Вычислить`. См. [#std770: Ограничения на использование Выполнить и Вычислить на сервере](https://v8std.ru/std/770/)
- изменение схем компоновки данных, в которых разрешено использование внешних функций, а так же загрузку схем компоновки данных из файлов

При использовании БСП внешний код надо подключать только средствами БСП:

- расширения - через механизм базовой функциональности
- внешние отчеты и обработки - через подсистему "Дополнительные отчеты и обработки"
- внешние компоненты - через подсистему "Внешние компоненты"
- для запуска внешних программ - См. [#std774: Безопасность запуска приложений](https://v8std.ru/std/774/)

#### 2.

По умолчанию требуется отключить интерактивное открытие внешних отчетов и обработок через меню __Файл - Открыть__. В том числе у администратора.

См. пп. 2.2 и 2.3 [#std488: Стандартные роли](https://v8std.ru/std/488/)

Администратор может разрешить интерактивное открытие.

#### При интерактивном открытии надо уведомлять об опасности действия
Изображение: Пример предупреждения из БСП (669.alert1.png)

#### 3.

Предупреждайте администратора об опасности подключения любого внешнего кода.

#### 3.1.

Предупреждение должно содержать:

#### Цитата

Внешний код, полученный из недостоверных источников (с которыми, например, нет договоренности о разработке такого кода), может нанести вред компьютерам пользователей, серверным компьютерам, а также данным в программе.

Дайте возможность администратору прервать загрузку, провести аудит, а потом заново повторить загрузку.

#### При загрузке расширения
Изображение: Предупреждение при загрузке расширения (669.alert2.png)

#### При загрузке дополнительной обработки
Изображение: Предупреждение при загрузке дополнительной обработки (669.alert3.png)

#### При загрузке внешней компоненты
Изображение: Предупреждение при загрузке внешней компоненты (669.alert4.png)

#### 3.2.

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

Механизм защиты от опасных действий платформы во всех случаях отключать запрещено.

[Руководство разработчика 7.10.2. Отключение механизма защиты от опасных действий](https://its.1c.ru/db/v8327doc/bookmark/dev/ti000001873)

#### 4.
Средства обновления конфигурации (из файлов .cf или .cfu), средства восстановления из резервной копии или загрузки из dt-файла

- должны быть доступны только администратору
- должно выполняться только интерактивно
- администратору надо показать предупреждение
- при получении обновления из сети Интернет, надо использовать защищенное соединение

#### 5.

Произвольные файлы могут содержать вредоносный код.

Предусмотрите блокировку загрузки файлов по списку разрешенных (запрещенных) расширений.

Открывать исполняемые файлы из программы запрещено. Даже если их разрешено загрузить и хранить в программе.

Вредоносный код может содержаться в макросах Microsoft Office. При работе с такими файлами используйте средства безопасности, заложенные в их программы просмотра. См [#std775: Безопасность программного обеспечения, вызываемого через открытые интерфейсы](https://v8std.ru/std/775/)

Используйте БСП подсистему "Работа с файлами".

#### 6.
Безопасность внешних компонент.

#### 6.1.
Внешние компоненты можно размещать:

- в макетах конфигурации - они являются частью конфигурации
- сторонние - они потенциально опасны

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

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

#### 6.2.
Сторонние внешние компоненты должны храниться в специальном справочнике.
Запись в такой справочник должен иметь только администратор.
Подключать сторонние внешние компоненты допустимо только по навигационной ссылке на реквизит справочника.

Не подключайте сторонние внешние компоненты по имени файла или по идентификатору программы. Так компоненту легко подменить.

#### 6.3.
Внешние компоненты в составе конфигурации должны хранится в макетах типа "Внешняя компонента". Макет не локализуется. Компоненты должны локализовываться через интерфейс компоненты.

#### 6.4.
Используйте БСП для подключение внешних компонент.

#### Неправильно

```bsl
ПодключитьВнешнююКомпоненту(...)
НачатьУстановкуВнешнейКомпоненты(...)
УстановитьВнешнююКомпоненту(...)
НачатьПодключениеВнешнейКомпоненты(...)
ЗагрузитьВнешнююКомпоненту(...)
```

#### Для подключения компоненты из макета
```bsl
ОбщегоНазначенияКлиент.ПодключитьКомпонентуИзМакета
```

#### Для подключения компоненты из макета на сервере
```bsl
ОбщегоНазначения.ПодключитьКомпонентуИзМакета
```

#### Для подключения компонент из хранилища внешних компонент
```bsl
ВнешниеКомпонентыКлиент.ПодключитьКомпоненту
```

#### Для подключения компонент из хранилища внешних компонент на сервере
```bsl
ВнешниеКомпоненты.ПодключитьКомпоненту
```

#### 7.
Загружать код из внешнего удаленного источника следует:

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

#### Пример установки защищенного соединения с проверкой подлинности сервера
```bsl
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL(, Новый СертификатыУдостоверяющихЦентровОС);
Соединение = Новый HTTPСоединение(Сервер,,,,,, ЗащищенноеСоединение);
```

Вне зависимости от протокола и типа канала, канал должен быть защищенным: `HTTPСоединение`, `FTPСоединение`, `WSПрокси`, `WSОпределения`, `WSСсылкаМенеджер.СоздатьWSПрокси`.

#### В БСП есть конструктор защищенного соединения
```bsl
ЗащищенноеСоединение = ОбщегоНазначенияКлиентСервер.НовоеЗащищенноеСоединение();
Соединение = Новый HTTPСоединение(Сервер,,,,,, ЗащищенноеСоединение);
```

#### 8.
Регламентные задания по-умолчанию запускаются под полными правами.
Установка безопасного режима не уменьшает прав пользователя.

Ограничивайте права в сеансе регламентного задания. Для этого программно создайте и укажите служебного пользователя.

Стратегии ограничения прав:

- пустой список ролей, вычисления без прав, чтение и изменение выполнять в привилегированном режиме установленном вручную, исполнение произвольного кода производить в безопасном режиме
- назначить реального пользователя (для одноразовых заданий ок)
- создавать специальный профиль и специальные роли для чтения таблиц

Для БСП в подсистеме "Регламентные задания" в начале обработчика регламентного задания разместите код:

#### В БСП есть установка служебного пользователя
```bsl
РегламентныеЗаданияСервер.УстановитьСлужебногоПользователяРегламентногоЗадания
```

#### См. также

- [#std770: Ограничения на использование Выполнить и Вычислить на сервере](https://v8std.ru/std/770/)
- [Облачные технологии](https://v8.1c.ru/platforma/oblachnye-tehnologii/)
- [#std678: Безопасность прикладного программного интерфейса сервера](https://v8std.ru/std/678/)
- [#std485: Использование привилегированного режима](https://v8std.ru/std/485/)

#### Проверки
[#bslls:UsingExternalCodeTools](https://v8std.ru/diagnostics/bslls/UsingExternalCodeTools/)

[#acc:472](https://v8std.ru/diagnostics/acc/472/)
[#acc:552](https://v8std.ru/diagnostics/acc/552/)
[#acc:553](https://v8std.ru/diagnostics/acc/553/)
[#acc:554](https://v8std.ru/diagnostics/acc/554/)
[#acc:555](https://v8std.ru/diagnostics/acc/555/)
[#acc:556](https://v8std.ru/diagnostics/acc/556/)
[#acc:1324](https://v8std.ru/diagnostics/acc/1324/)
#### Источник

https://its.1c.ru/db/v8std#content:669

Использован конструктор "Новый ЗащищенноеСоединениеOpenSSL". АПК:1324

Небезопасное подключение внешних компонент. АПК:472

Небезопасное подключение внешней обработки. АПК:552

Небезопасное подключение внешнего отчета. АПК:553

Небезопасное подключение расширения конфигурации. АПК:554

Создание объекта типа "ОписаниеЗащитыОтОпасныхДействий". АПК:555

Вызов функции БСП "ОбщегоНазначения.ОписаниеЗащитыБезПредупреждений()". АПК:556

Использование возможностей выполнения внешнего кода BSLLS:UsingExternalCodeTools

Использование привилегированного режима #std485

Стандартные роли #std488

Безопасность прикладного программного интерфейса сервера #std678

Ограничения на использование Выполнить и Вычислить на сервере #std770

Безопасность запуска приложений #std774

Безопасность программного обеспечения, вызываемого через открытые интерфейсы #std775

Ограничение на выполнение внешнего кода #std669


стандарт 677

ID: #std677

# Использование общих реквизитов

#### 1.

Общие реквизиты применяйте для двух задач:

- разделение данных (`Разделение данных = Разделять`);
- добавление служебного реквизита сразу в несколько объектов (`Разделение данных = Не использовать`).

#### 2.

Общие реквизиты без разделения данных используйте только для инфраструктурных задач конфигурации, когда данные нужно хранить прямо в прикладных объектах.

Не переносите в общие реквизиты обычные прикладные поля вроде `Ответственный`, `Комментарий`, `Организация` только ради удобства.

Учитывайте, что права на общие реквизиты настраиваются отдельно от прав на объекты, куда они добавлены.

#### 3.

Порядок общих реквизитов-разделителей в дереве метаданных выбирайте в соответствии с порядком установки связанных параметров сеанса.
Подробности: [#std413: Использование параметров сеанса](https://v8std.ru/std/413/)

#### См. также

- [#std413: Использование параметров сеанса](https://v8std.ru/std/413/)
- [#std668: Разработка ролей в библиотеках](https://v8std.ru/std/668/)

#### Источник

https://its.1c.ru/db/v8std#content:677

Использование параметров сеанса #std413

Разработка ролей в библиотеках #std668

Использование общих реквизитов #std677


стандарт 678

ID: #std678

# Безопасность прикладного программного интерфейса сервера

#### 1.

Злоумышленник может вызвать серверный код с клиента. Например, он может выполнять запросы по HTTP, пытаясь повторить поведение клиента платформы. Своими действиями злоумышленник не должен получить несанкционированный доступ к данным пользователей или нарушить работоспособность сервера.

#### 1.1.

Все серверные функции, доступные для вызова с клиента представляют потенциальную угрозу.

- Экспортные процедуры и функции из общих модулей с флажками `Сервер` и `Вызов сервера`. Такие функции можно вызывать напрямую с клиента. [#std679: Ограничение на установку признака «Вызов сервера» у общих модулей](https://v8std.ru/std/679/)
- Функции модулей форм с директивами компиляции `&НаСервере`, `&НаСервереБезКонтекста`. Такие функции можно вызывать в контексте клиента после получения формы, даже когда функции не экспортные.

#### Уязвимость

```bsl
&НаКлиенте
Процедура УволитьСотрудника(Команда)

    Если ДатаРегистрацииУвольнения > ДатаЗапрета Тогда
        ЗарегистрироватьУвольнение();
    КонецЕсли;

КонецПроцедуры

&НаСервере
Процедура ЗарегистрироватьУвольнение()
    ...
КонецПроцедуры
```

```bsl
ПараметрыФормы = Новый Структура("Ключ", ВыбранныйСотрудник);
Форма = ПолучитьФорму("Справочник.Сотрудники.ФормаЭлемента", ПараметрыФормы);
Форма.ЗарегистрироватьУвольнение();
```

#### 1.2.

При разработке формы исключите из кода ее модуля бизнес-логику. Код формы должен содержать только клиент-серверное взаимодействие и обработку реквизитов формы.

#### 1.3.

Тщательно тестируйте код, в котором устанавливается привилегированный режим или который расположен в общих модулях с флажком `Привилегированный`. [#std485: Использование привилегированного режима](https://v8std.ru/std/485/)

#### 2.

Любые возможности конфигурации исполнить "внешний" код или произвольные тексты запросов на сервере, не являющиеся частью программы, потенциально опасны.

- Внешние отчеты и обработки
- COM-объекты
- Внешние компоненты

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

Такие возможности создают угрозы [#std669: Ограничение на выполнение «внешнего» кода](https://v8std.ru/std/669/)

- Работоспособности сервера
- Порчу или хищение данных
- Зависание или зацикливание рабочего процесса
- Утечки памяти
- Ресурсоемкие операции и запросы

#### 3.

Клиентское приложение (тонкий клиент, веб-браузер) не гарантирует безопасность данных, переданных на сторону клиента. Вредоносные программы (вирусы, зловреды) могут перехватить и прочитать данные, полученные клиентом.

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

#### Проверки
[#bslls:SetPrivilegedMode](https://v8std.ru/diagnostics/bslls/SetPrivilegedMode/)

#### Источник

https://its.1c.ru/db/v8std#content:678

Злоумышленник может вызвать серверный код с клиента. Например, он может выполнять запросы по HTTP, пытаясь повторить поведение клиента платформы. Своими действиями злоумышленник не...

Использование привилегированного режима BSLLS:SetPrivilegedMode

Ограничение на установку признака «Вызов сервера» у общих модулей #std679


стандарт 679

ID: #std679

# Ограничение на установку признака «Вызов сервера» у общих модулей

#### 1.

Не устанавливайте признак `Вызов сервера` у всех серверных общих модулей «по умолчанию».

В модулях с `Вызов сервера` размещайте только API, который действительно вызывается с клиента и:

- не раскрывает пользователю лишние данные;
- не выполняет действия, которые ему не разрешены.

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

Серверные процедуры и функции, не предназначенные для вызова с клиента,
размещайте в серверных модулях без признака `Вызов сервера`.

Особого внимания требует код:

- который устанавливает привилегированный режим;
- который размещен в модулях с признаком `Привилегированный`.

#### 2.1.

В управляемом приложении работа с экземплярами объектов (`СправочникОбъект`, `ДокументОбъект` и т.п.)
должна выполняться на сервере.

Поэтому в клиентском коде не создавайте и не получайте такие объекты:

- в клиентских общих модулях
  (в том числе при использовании директивы `ТолстыйКлиентУправляемоеПриложение`);
- в обычных формах, запущенных в управляемом режиме.

В частности, это важно для толстого клиента в режиме управляемого приложения.

Так вы исключаете:

- выполнение кода модулей объектов и подписок на события на клиенте;
- избыточные серверные вызовы из этого кода.

#### 2.2.

Если конфигурация не рассчитана на работу в толстом клиенте (управляемое приложение, клиент-сервер),
снимите в свойствах конфигурации флажок
`Толстый клиент (управляемое приложение, режим клиент-сервер)`.

Это уменьшает ложные ошибки при проверке конфигурации.

#### См. также

- [#std678: Безопасность прикладного программного интерфейса сервера](https://v8std.ru/std/678/)
- [#std469: Правила создания общих модулей](https://v8std.ru/std/469/)
- [#std680: Поддержка толстого клиента, управляемое приложение, клиент-сервер](https://v8std.ru/std/680/)

#### Источник

https://its.1c.ru/db/v8std#content:679

Не устанавливайте признак Вызов сервера у всех серверных общих модулей «по умолчанию».

Правила создания общих модулей #std469

Поддержка толстого клиента, управляемое приложение, клиент-сервер #std680


стандарт 680

ID: #std680

# Поддержка толстого клиента, управляемое приложение, клиент-сервер

#### 1.

В управляемом режиме иногда требуется поддержка запуска толстого клиента (режим управляемого приложения).
Причина — часть возможностей, которые есть в обычном приложении, но отсутствуют в управляемом.
Подробнее: [#metod3266: Функциональность обычного приложения, отсутствующая в управляемом приложении](https://v8std.ru/metod8dev/3266/)

#### 2.

В конфигурациях для управляемого приложения обычно предполагается, что в клиент-серверном режиме код модулей:

- менеджера;
- объекта;
- сеанса;

компилируется и выполняется только на сервере.

В этих модулях часто есть обращения к общим модулям, доступным только на сервере.

Однако в толстом клиенте (управляемое приложение, клиент-сервер) эти модули могут компилироваться и выполняться на клиенте.
Например:

- при явном создании объекта в клиентском коде;
- при неявных вызовах платформой обработчиков модулей менеджера и модуля сеанса на клиенте.

Из-за этого возникают ошибки и лишние сообщения проверки конфигурации.

Чтобы исключить незапланированную компиляцию и выполнение на клиенте:

- в модулях объектов полностью исключайте клиентский контекст инструкцией препроцессора;
- в модуле сеанса полностью исключайте клиентский контекст инструкцией препроцессора;
- в модулях менеджеров всех объектов метаданных полностью исключайте клиентский контекст инструкцией препроцессора.

#### Пример для модуля объекта

```bsl
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
    ...
#Иначе
    ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли
```

#### Пример для модуля сеанса

```bsl
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
    ...
#КонецЕсли
```

#### Пример для модуля менеджера

```bsl
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
    ...
#КонецЕсли
```

Если в модуле менеджера формируется представление через обработчики `ОбработкаПолученияПредставления` и `ОбработкаПолученияПолейПредставления`, то в толстом клиенте (управляемое приложение, клиент-сервер) представление будет формироваться по умолчанию, без вызова этих обработчиков.

Обработчики `ОбработкаПолученияДанныхВыбора` и `ОбработкаПолученияФормы` вызываются только на сервере, и это ограничение на них не распространяется.

#### Проверки
[#v8cs:module-accessibility-at-client](https://v8std.ru/diagnostics/v8-code-style/module-accessibility-at-client/)

#### 3.

Если это ограничение нужно снять, обеспечьте работу на клиенте:

- обработчиков `ОбработкаПолученияПредставления` и `ОбработкаПолученияПолейПредставления`;
- кода подписок на эти события.

Для этого:

- вынесите код обработчиков за инструкции препроцессора из п. 2;
- разместите обработчики подписок в клиент-серверных модулях;
- при переходе на сервер используйте общие модули с признаком `Вызов сервера`;
- не передавайте мутабельные типы (`СправочникОбъект`, `ДокументОбъект` и т.п.) через параметры и возвращаемые значения.

Не устанавливайте признак `Вызов сервера` всем модулям с признаком `Сервер`.
См. [#std679: Ограничение на установку признака «Вызов сервера» у общих модулей](https://v8std.ru/std/679/)

#### Неправильно

```bsl
Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)

    Взаимодействия.ОбработкаПолученияПредставления(Данные, Представление);
    СтандартнаяОбработка = Ложь;

КонецПроцедуры
```

#### Правильно

```bsl
Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)

    ВзаимодействияВызовСервера.ОбработкаПолученияПредставления(Данные, Представление);
    СтандартнаяОбработка = Ложь;

КонецПроцедуры
```

#### 4.

Для расстановки фрагментов кода с инструкциями препроцессора можно использовать [обработку с
ИТС](https://its.1c.ru/db/files/1CITS/EXE/V8Std/%D0%90%D0%B2%D1%82%D0%BE%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%9A%D0%BE%D0%B4%D0%B0%D0%98%D0%9B%D0%BE%D0%BA%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F/%D0%90%D0%B2%D1%82%D0%BE%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%9A%D0%BE%D0%B4%D0%B0%D0%98%D0%9B%D0%BE%D0%BA%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F.zip).

#### См. также

- [#std469: Правила создания общих модулей](https://v8std.ru/std/469/)
- [#std679: Ограничение на установку признака «Вызов сервера» у общих модулей](https://v8std.ru/std/679/)
- [Обработчики событий получения представления объектов](https://its.1c.ru/db/v8std/content/746/hdoc)

#### Проверки

[#acc:256](https://v8std.ru/diagnostics/acc/256/)
[#acc:361](https://v8std.ru/diagnostics/acc/361/)
[#acc:362](https://v8std.ru/diagnostics/acc/362/)
#### Источник

https://its.1c.ru/db/v8std#content:680

В управляемом режиме иногда требуется поддержка запуска толстого клиента (режим управляемого приложения). Причина — часть возможностей, которые есть в обычном приложении, но...

В объекте "Подписка на событие" использован обработчик из общего модуля, не являющегося клиент-серверным. АПК:256

Серверный код не заключен в инструкцию препроцессора: "#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда...". АПК:361

Обработчик события заключен в инструкцию препроцессора: "#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда...". АПК:362

Метод или переменная доступны НаКлиенте (module-accessibility-at-client)

Правила создания общих модулей #std469