Контакты

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

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

Структура конфигурации представлена на рисунке.

(16.22 килобайт) Кол-во скачиваний: 64

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

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

//Проведение по регистру

КонецЦикла;

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

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

|ВЫБРАТЬ
| Док.Номенклатура,

|ИЗ
| (ВЫБРАТЬ

| ИЗ
| Документ.Расходная.Товары
| ГДЕ
| Ссылка = &Ссылка
| СГРУППИРОВАТЬ ПО Номенклатура) КАК Док
| ЛЕВОЕ СОЕДИНЕНИЕ
Номенклатура В
| (ВЫБРАТЬ РАЗЛИЧНЫЕ
| Номенклатура
| ИЗ
| Документ.Расходная.Товары
| ГДЕ
| Ссылка = &Ссылка)) КАК Рег
| ПО

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

Временные таблицы

Не помню уже с какого релиза в запросах стало можно использовать временные таблицы. Для этого используется объект «Менеджер временных таблиц». Фактически менеджер временных таблиц описывает пространство имен временных таблиц и отвечает за их создание и уничтожение в базе данных.

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

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

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

МВТ = Новый МенеджерВременныхТаблиц;

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

Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МВТ;
Запрос.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ
| Номенклатура
|ПОМЕСТИТЬ СписокТоваров
|ИЗ
| Документ.Расходная.Товары
|ГДЕ
| Ссылка = &Ссылка";

Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МВТ;
Запрос.Текст = "
|ВЫБРАТЬ
| Док.Номенклатура,
| Док.Количество КАК Док_Количество,
| ЕСТЬNULL(Рег.КоличествоОстаток,0) КАК Рег_Количество
|ИЗ
| ДокТЧ КАК Док
| ЛЕВОЕ СОЕДИНЕНИЕ
| РегистрНакопления.ОстаткиТоваров.Остатки(,
| Номенклатура
| ИЗ
| ПО
| Док.Номенклатура = Рег.Номенклатура";

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл

//Проверка отрицательных остатков

//Проведение по регистру

КонецЦикла;

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

При использовании временных таблиц в тексте запроса применяют инструкцию Поместить для создания новой временной таблицы, в этом случае в результат запроса система передает не содержимое этой таблицы (см прим 1 и прим 2 в тексте выше), а количество записей помещенных во временную таблицу, по желанию можно не принимать это значение.

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

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

Пакетные запросы

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

В пакетном запросе фактически можно описать несколько запросов, как связанных между собой использованием временных таблиц, так и не связанных (можно, но не понятно зачем?). В итоге можно выполнить последовательно все запросы и принять в результате либо массив с результатами исполнения каждого запроса, либо результат последнего. Для получения массива с результатами запроса применяют метод ВыполнитьПакет() объекта запрос, а для получения результата последнего запроса ВыполнитьЗапрос() .

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

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

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
| Номенклатура, СУММА(Количество) КАК Количество
|ПОМЕСТИТЬ ДокТЧ
|ИЗ
| Документ.Расходная.Товары
|ГДЕ
| Ссылка = &Ссылка
|СГРУППИРОВАТЬ ПО Номенклатура
|;
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| Номенклатура
|ПОМЕСТИТЬ СписокТоваров
|ИЗ
| Документ.Расходная.Товары
|ГДЕ
| Ссылка = &Ссылка
|;
|ВЫБРАТЬ
| Док.Номенклатура,
| Док.Количество КАК Док_Количество,
| ЕСТЬNULL(Рег.КоличествоОстаток,0) КАК Рег_Количество
|ИЗ
| ДокТЧ КАК Док
| ЛЕВОЕ СОЕДИНЕНИЕ
| РегистрНакопления.ОстаткиТоваров.Остатки(,
| Номенклатура В(ВЫБРАТЬ РАЗЛИЧНЫЕ
| Номенклатура
| ИЗ
| СписокТоваров КАК СписокТоваров)) КАК Рег
| ПО
| Док.Номенклатура = Рег.Номенклатура";

Пока Выборка.Следующий() Цикл

//Проверка отрицательных остатков

//Проведение по регистру

КонецЦикла;

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

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

После выполнения запроса в переменную МассивРезультатов у нас попадет 3 элемента. Первые два будут содержать число характеризующее количество записей помещенных во временные таблицы ДокТЧ и СписокТоваров , а третий будет содержать выборку с полями Номенклатура , Док_Количество и Рег_Количество .

В переменную РезультатЗапроса попадет только выборка.

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

Платформа «1С Предприятие» позволяет выполнить последовательно несколько запросов за один раз. В 1С это называется пакетом запросов. В рамках одного пакета каждый запрос разделяется «точкой с запятой».

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

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

Еще одна важная деталь в пользу пакетных запросов в 1С – это то, что в отличие от мы можем получить отдельно результат каждого запроса в пакете.

Пример создания пакета запросов на языке 1С

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

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

Получите 267 видеоуроков по 1С бесплатно:

Хозрасчетный.Ссылка,
Хозрасчетный.Родитель,
Хозрасчетный.Код,
Хозрасчетный.КодБыстрогоВыбора,
Хозрасчетный.Наименование,
Хозрасчетный.Вид,
Хозрасчетный.Забалансовый,
Хозрасчетный.Количественный,
ИЗ
ПланСчетов.Хозрасчетный КАК Хозрасчетный
ГДЕ
Хозрасчетный.Ссылка = &Счет
;
////////////////////////////////////////////////////////////////////////////////

ВЫБРАТЬ
ХозрасчетныйВидыСубконто.НомерСтроки КАК НомерСтроки,
ХозрасчетныйВидыСубконто.ВидСубконто КАК ВидСубконто,
ХозрасчетныйВидыСубконто.ВидСубконто.Наименование КАК Наименование,
ХозрасчетныйВидыСубконто.ВидСубконто.ТипЗначения КАК ТипЗначения,
ХозрасчетныйВидыСубконто.ТолькоОбороты КАК ТолькоОбороты,
ХозрасчетныйВидыСубконто.Суммовой КАК Суммовой
ИЗ
ПланСчетов.Хозрасчетный.ВидыСубконто КАК ХозрасчетныйВидыСубконто
ГДЕ
ХозрасчетныйВидыСубконто.Ссылка = &Счет
УПОРЯДОЧИТЬ ПО
ХозрасчетныйВидыСубконто.НомерСтроки

У меня это выглядит так:

Теперь перейдем в конструктор запросов. Здесь нас будет интересовать закладка «Пакет запросов»:

Как видим, у нас появился пакет из двух запросов. Кликнув два раза на любом из них, можно перейти к его редактированию:

Нажмем кнопку «Ок» и попробуем посмотреть результат выполнения пакетного запроса.

Установим параметр «Счет». Можно выбрать любой счет из плана счетов. Как Вы уже, наверное, догадались, данный пакет запросов должен получить свойства счета. Нажимаем «Выполнить» и смотрим результат:

Методы Выполнить() и ВыполнитьПакет()

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

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

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

Пакетные запросы появились только в версии 8.1.11.67.4.

Вот текст запроса:

ВЫБРАТЬ Т1.Зн ПОМЕСТИТЬ ВТБуквы ИЗ (ВЫБРАТЬ "А" КАК Зн ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Б") КАК Т1;

ВЫБРАТЬ Т1.Зн ПОМЕСТИТЬ ВТЦифры ИЗ (ВЫБРАТЬ "1" КАК Зн ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "2") КАК Т1;

ВЫБРАТЬ ТБ.Зн, ТЦ.Зн, ТБ.Зн+ТЦ.Зн ИЗ ВТБуквы КАК ТБ, ВТЦифры КАК ТЦ

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

На рисунке представлен образец выполнения запроса:

А теперь немного из опыта. Зачем нужны пакетные запросы.

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

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

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

Кроме того, если используется система компоновки данных (СКД), она грамотно отбирает нужные поля и минимизирует весь пакет запросов.

Если у запросов был метод Запрос.Выполнить() то теперь появился метод Запрос.ВыполнитьПакет() , который возвращает все таблицы из пакета, в виде массива.

Анонс пакетных запросов на сайте 1с находится здесь: http://v8.1c.ru/overview/release_8_1_11/#Functional

История из жизни

Объясню, что меня подвигло на пакетные запросы.

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

Так вот, мы заносим список всех ошибок в таблицу КодыОшибок - там содержится код ошибки и подстрока поиска.

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

Но ошибка может быть и не распознана, т.е. флаг «Ошибка » стоит, а текст ошибки не выдал нам код ошибки.

Делаем левое соединение, там где код ошибки есть NULL, даем код ошибки «Прочие ошибки » .

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

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

Я просто еще раз соединил все строки с ошибками со всеми строками, для которых были найдены ошибки, и добавил все-таки вид ошибки «Прочие ошибки».

В статье рассказывается о механизме пакетных запросов, реализованных в платформе «1С:Предприятие». Прочитав статью, вы узнаете:

  • Что такое пакетные запросы и для чего они нужны?
  • Как создать пакет запросов при помощи конструктора запросов?
  • Как вернуть массив результатов для каждого запроса из пакета?

Применимость

Материал актуален для текущих версий платформы «1С:Предприятие» редакции 8.3

Назначение пакета запросов

Платформа позволяет работать с пакетами запросов. Получаем возможность выполнить несколько запросов «за раз». В пакетном запросе тексты запросов разделяются символом «;» (точка с запятой).

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

Пакеты запросов позволяют достичь поэтапного выполнения запроса. Для этого в пакетном запросе сначала происходит создание временных таблиц, далее – их совместное использование (соединение, объединение, фильтры) для получения итогового результата запроса. Также важно отметить, что использование временных таблиц в пакетных запросах позволяет улучшить читаемость текста запроса.

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

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

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

Создание пакета запросов при помощи конструктора

Отдельные запросы, входящие в пакет, отделяются в тексте символом «;» (точка с запятой). Чтобы не разделять текст запроса вручную, можно использовать для этого конструктор запросов.
В конструкторе запросов есть отдельная закладка для пакетов запросов. Запросы в пакет можно добавлять при помощи соответствующей кнопки на командной панели, а также передвигать вверх или вниз.

Визуальное отображение отдельных запросов – закладки в правой части конструктора, при помощи которых можно перейти к редактированию текста отдельного запроса. На этих закладках для временных таблиц выводятся имена, для запросов на выборку данных – «Запрос пакета 2» и т.п., на уничтожение – «– ИмяВТ».

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

Выполнение запросов пакета

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

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

Кроме метода Выполнить() , последовательно выполняющего все запросы пакета и возвращающего результат последнего запроса в пакете, в платформе существует еще один метод – ВыполнитьПакет() .

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

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

Данная статья рассчитана на читателей, которые знакомы с языком SQL.

Язык запросов в 1С, применяющийся начиная с версии 8, сегодня стал полезным инструментом для работы с базами данных, который позволяет читать из них, но не записывать. Синтаксически язык запросов очень схож с языком SQL, но на русском языке.

Ниже представлена таблица соответствия основных операторов языка запросов и SQL:

Операторы языка запросов 1С

Оператор SQL

РАЗЛИЧНЫЕ

СОЕДИНЕНИЕ

СГРУППИРОВАТЬ ПО

ОБЪЕДИНИТЬ

УПОРЯДОЧИТЬ ПО

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

Выполнение запроса 1С из программного кода осуществляется при помощи объекта встроенного языка «Запрос». Пример написания запроса к базе данных с использованием встроенного языка программирования:

Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Синоним.Ссылка КАК Ссылка |ИЗ | Справочник.Справочник1 КАК Синоним"; Выборка = Запрос.Выполнить().Выбрать(); Пока Выборка.Следующий() Цикл // Вставить обработку выборки ВыборкаДетальныеЗаписи КонецЦикла;

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

Параметры запроса хранятся в свойстве «Параметры» (в данном случае это структура, поэтому все методы структуры тут применимы – вставить, удалить и т.д.).

Пример установки параметра «Запрос.Параметры.Вставить» («Справочник», СправочникСсылка). В запросе обратиться к параметрам можно через амперсанд «&Справочник». Ниже пример запроса с использованием параметров:

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

Напомним, что язык запросов предназначен только для чтения данных из базы, поэтому в нем отсутствуют аналоги таких операторов SQL, как INS ERT и UPDATE. Данные можно модифицировать только через объектную модель встроенного языка программирования 1С. Также в языке запросов 1С существуют операторы, аналогов которых нет в SQL, например:

  • В ИЕРАРХИИ
  • ПОМЕСТИТЬ
  • ИНДЕКСИРОВАТЬ ПО

В ИЕРАРХИИ – позволяет выбрать все элементы иерархического справочника, которые входят в иерархию переданной ссылки. Пример запроса с использованием В ИЕРАРХИИ :

ВЫБРАТЬ Товары.Ссылка, Товары.Артикул ИЗ Справочник.Товары КАК Товары ГДЕ Товары.Ссылка В ИЕРАРХИИ(&Цитрусовые)"

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

Также, к примеру, стоит задача найти товар с именем «Ручка». Товар должен входить в иерархию «Канц. Товаров», то есть нам не надо искать дверную ручку. Структура номенклатуры в этом случае такова:

Канцелярия

|_ Ручки перьевые |_ Ручка красная |_ Ручка синяя |_ Ручки чернильные |_ Линейки

Фурнитура

|_ Ручки дверные |_ Ручка дверная простая |_ Ручка дверная люкс

Пишем такой запрос:

ВЫБРАТЬ Товары.Ссылка, Товары.Артикул ИЗ Справочник.Товары КАК Товары ГДЕ Товары.Наименование Подобно "Ручка%" И Товары.Ссылка В ИЕРАРХИИ(&Канцелярия)"

При использовании конструкции В ИЕРАРХИИ необходимо учитывать, что если в параметр «Канцелярия» передать пустую ссылку, выполнение запроса замедлится, так как платформа будет проверять каждый элемент на принадлежность корню.

ПОМЕСТИТЬ – Данный оператор помещает результат во временную таблицу. Пример запроса:

ВЫБРАТЬ Пользователи.Ссылка КАК Ссылка, Пользователи.Родитель КАК Родитель, Пользователи.Наименование КАК Наименование ПОМЕСТИТЬ ОтобранныеПользователи ИЗ Справочник.Пользователи КАК Пользователи ГДЕ Пользователи.Ссылка = &Справочник; ВЫБРАТЬ ОтобранныеПользователи.Ссылка КАК Ссылка, ОтобранныеПользователи.Родитель КАК Родитель, ОтобранныеПользователи.Наименование КАК Наименование ИЗ ОтобранныеПользователи КАК ОтобранныеПользователи

Данный запрос на SQL будет выполнен несколькими запросами:

  • Создание временной таблицы (платформа умеет «переиспользовать» ранее созданные временные таблицы, поэтому создание происходит не всегда);
  • Помещение данных во временную таблицу;
  • Выполнение основного запроса, а именно SEL ECT из этой временной таблицы;
  • Уничтожение/очистка временной таблицы.

Временная таблица может быть уничтожена явно, через конструкцию УНИЧТОЖИТЬ , либо неявно – при закрытии менеджера временных таблиц.

У объекта «Запрос» встроенного языка программирования есть свойство «МенеджерВременныхТаблиц», которое предназначено для работы с временными таблицами. Пример кода:

МВТ = Новый МенеджерВременныхТаблиц(); Запрос = Новый Запрос; Запрос.МенеджерВременныхТаблиц = МВТ;

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

МВТ.Закрыть();

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

ИНДЕКСИРОВАТЬ ПО – этот оператор применяется совместно с оператором ПОМЕСТИТЬ. При создании временной таблицы этим оператором можно проиндексировать создаваемую таблицу, что существенно ускоряет работу с ней (но только, если индекс подходит под ваш запрос).

Бесплатная консультация эксперта

Спасибо за Ваше обращение!

Специалист 1С свяжется с вами в течение 15 минут.

Особенности некоторых операторов языка запросов

ДЛЯ ИЗМЕНЕНИЯ данный оператор предназначен для блокировки определенной таблицы запроса (или всех таблиц, которые участвуют в запросе). Блокировка осуществляется наложением U блокировки на таблицу. На SQL это реализуется через hint UPDLOCK. Данная конструкция необходима для предотвращения блокировок типа deadlock. Пример запроса с конструкцией ДЛЯ ИЗМЕНЕНИЯ:

ВЫБРАТЬ Пользователи.Ссылка КАК Ссылка, Пользователи.Родитель КАК Родитель, Пользователи.Наименование КАК Наименование ИЗ Справочник.Пользователи КАК Пользователи ЛЕВОЕ СОЕДИНЕНИЕ Справочник.РФК КАК РФК ПО Пользователи.РФК = РФК.Ссылка ДЛЯ ИЗМЕНЕНИЯ Справочник.Пользователи

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



СОЕДИНЕНИЕ – запрос поддерживает соединения ЛЕВОЕ/ПРАВОЕ, ПОЛНОЕ, ВНУТРЕННЕЕ, что соответствует соединениям в SQL – LEFT/RIGHT JOIN, OUTER JOIN, INNER JOIN.

Однако при использовании конструктора запросов вы не сможете сделать ПРАВОЕ СОЕДИНЕНИЕ. Конструктор просто будет менять местами таблицы, но оператор будет всегда левый. По этой причине в 1С никогда не встретишь применения правого соединения.

Синтаксически соединение выглядит так:

ВЫБРАТЬ Таблица1.Ссылка КАК Ссылка ИЗ Справочник.Справочник1 КАК Таблица1 ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Справочник2 КАК Таблица2 ПО Таблица1.Реквизит = Таблица2.Реквизит

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

ВЫБРАТЬ Таблица1.Ссылка КАК Ссылка ИЗ Справочник.Справочник1 КАК Таблица1 ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Справочник2 КАК Таблица2 ПО ИСТИНА

Как видно из примера, задан ключ соединения ПО ИСТИНА , то есть каждая строка одной таблицы соответствует строке другой. Тип соединения (ЛЕВОЕ, ПРАВОЕ, ПОЛНОЕ, ВНУТРЕННЕЕ) не важен, если у вас есть строки в обеих таблицах, но если в какой-то из таблиц нет строк (пуская таблица) – результат будет отличаться. Например, при использовании ВНУТРЕННЕЕ соединение результат будет пустой. При использовании ЛЕВОЕ/ПРАВОЕ соединение в результате будет или не будет данных в зависимости от того, к какой таблице мы присоединяемся – с данными или нет. При использовании ПОЛНОГО соединения данные будут всегда (естественно, только одной таблицы, так как в другой пустота), выбор типа соединения зависит от конкретной прикладной задачи.

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



ПОДОБНО. В отличие от аналогичного оператора языка SQL – LIKE, шаблон для ПОДОБНО можно задать, используя только некоторые спец символы:

  • % (процент): последовательность, содержащая любое количество произвольных символов;
  • _ (подчеркивание): один произвольный символ;
  • / - следующий символ нужно интерпретировать как обычный символ.

ИТОГИ ПО аналогом на SQL можно назвать оператор ROLLUP. Пример использования оператора ИТОГИ:

ВЫБРАТЬ Товары.Цена КАК Цена, Товары.Товар КАК Товар ИЗ Справочник.Номенклатура КАК Товары ИТОГИ СРЕДНЕЕ(Цена) ПО Товар

Результат будет такой:

Кровать

9833,333

Утюг

Ручка

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

Работа с пакетными запросами

1С позволяет работать с пакетами запросов. В пакетном запросе тексты запросов разделяются точкой с запятой (;). Выполнение пакетного запроса 1С осуществляется последовательно. Пример текста пакетного запроса:

ВЫБРАТЬ Пользователи.Ссылка КАК Ссылка, Пользователи.Родитель КАК Родитель, Пользователи.Наименование КАК Наименование ИЗ Справочник.Пользователи КАК Пользователи;
ВЫБРАТЬ ГрафикРаботы.Пользователь КАК Пользователь, ГрафикРаботы.Дата КАК Дата, ГрафикРаботы.РабочихЧасов КАК РабочихЧасов ИЗ РегистрСведений.ГрафикРаботы КАК ГрафикРаботы

Для получения результата всех запросов, входящих в пакет, необходимо воспользоваться методом объекта запроса «ВыполнитьПакет», вместо «Выполнить». Данный метод последовательно выполняет все запросы. Результат запроса – массив результатов для каждого запроса из пакета, а последовательность расположения в массиве такая же, как последовательность запросов в тексте пакета.

Рассматривая язык запросов, стоит упомянуть о такой особенности, как виртуальные таблицы. Виртуальные таблицы отсутствуют в базе данных, это своеобразная обертка, которая выполняется на стороне СУБД как запрос с использованием подзапросов. Пример запроса 1С с использованием виртуальных таблиц:

ВЫБРАТЬ РегистрОбязательствОбороты.Обязательство КАК Обязательство ИЗ РегистрНакопления.РегистрОбязательств.Обороты() КАК РегистрОбязательствОбороты

Такой запрос на СУБД будет выглядеть так:

SEL ECT T1.Fld25931RRef FR OM (SELECT T2._Fld25931RRef AS Fld25931RRef, CAST(SUM(T2._Fld25936) AS NUMERIC(38, 8)) AS Fld25936Turnover_, CAST(SUM(T2._Fld25937) AS NUMERIC(38, 8)) AS Fld25937Turnover_ FR OM dbo._AccumRgTn25938 T2 WH ERE ((T2._Fld949 = @P1)) AND ((T2._Fld25936 @P2 OR T2._Fld25937 @P3)) GROUP BY T2._Fld25931RRef HAVING (CAST(SUM(T2._Fld25936) AS NUMERIC(38, 8))) 0.0 OR (CAST(SUM(T2._Fld25937) AS NUMERIC(38, 8))) 0.0) T1>>>>

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

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



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



В тексте запроса это выглядит так:

РегистрНакопления.РегистрОбязательств.Обороты(, Операция = &Операция) КАК РегистрОбязательствОбороты

Для удобства написание запросов, то есть создания текстов запросов, в 1С существует конструктор, который можно вызвать через контекстное меню (правой кнопкой мыши):



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


Конструктор запросов является очень гибким визуальным инструментом для создания запросов любой сложности. Он доступен только в режиме конфигуратора. В режиме Предприятия есть так называемая «Консоль запросов» – это внешняя обработка, поставляемая на диске ИТС. Для управляемого приложения консоль запросов можно скачать на сайте its.1c.ru.

Описание работы в конструкторе запросов выходит за рамки тематики данной статьи, поэтому подробно рассматриваться не будет.

Причины неоптимальной работы запросов

Ниже приведен список основных причин (но не всех), которые приводят к замедлению выполнения запроса.

  • Использования соединения с подзапросами

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

  • Использование виртуальных таблиц в соединениях запроса

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

  • Использование условий в запросе, неподходящих под существующие индексы

Если в условиях запроса (в операторе ГДЕ или в условиях виртуальной таблицы) используются поля, которые не все входят в индекс, данный запрос будет выполнен с использованием SQL конструкции table scan или index scan (полностью или частично). Это скажется не только на времени выполнения запроса, но также будет наложена избыточная S блокировка на лишние строки, что в свою очередь может привести к эскалации блокировок, то есть будет заблокирована вся таблица.

  • Использование ИЛИ в условиях запроса

Использование логического оператора ИЛИ в конструкции ГДЕ может также приводить к сканированию таблицы (table scan). Это происходит из-за того, что СУБД не может корректно использовать индекс. Вместо ИЛИ можно применить конструкцию ОБЪЕДИНИТЬ ВСЕ.

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

Не рекомендуется получать значения через точку (в конструкции ВЫБРАТЬ, ГДЕ ), поскольку если реквизит объекта окажется составным типом, соединение будет происходить с каждой таблицей, входящей в этот составной тип. В результате запрос на СУБД будет значительно усложнен, это может помешать оптимизатору в выборе корректного плана выполнения запроса.



Понравилась статья? Поделитесь ей