Добавил:
sora.alai.102@gmail.com Делаю работы на заказ. Какие именно? Пишите. Или регайтесь на бирже, где я работаю: https://vsesdal.com/promo?ref=748568 Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Хрусталева Е. Ю. Язык запросов 1С-Предприятия 8 (2013)

.pdf
Скачиваний:
2179
Добавлен:
25.11.2018
Размер:
31.3 Mб
Скачать

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

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

Поэтому вместо вложенных запросов в соединениях ВСЕГДА нужно использовать временные таблицы. При этом их необходимо проиндексировать по полям, участвующим в условии соединения (листинг 4.14).

Листинг 4.14. Выполнение запроса для получения остатков номенклатуры, содержащихся в документе, – правильный вариант

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

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

И, наконец, приведенный запрос лучше читается, проще для понимания и отладки.

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

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

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

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

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

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

РегистрНакопления.ТоварыНаСкладах.Остатки(), можно переписать следующим образом (листинг 4.15).

Листинг 4.15. Выполнение запроса для получения остатков номенклатуры, содержащихся в документе, – правильный вариант

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

Не использовать вложенные запросы в условиях соединения

По тем же причинам, по которым «вредно» использовать соединения с вложенными запросами (раздел "Соединения с вложенными запросами"), также потенциально опасно и использование вложенных запросов в условиях соединения ПО.

Исключить получение поля «Ссылка» через точку

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

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

Поэтому совершенно излишним является получение в запросе поля Ссылка через точку от полей ссылочного типа. Например, требуется отобрать документы по значению ссылочного поля Склад. В этом случае следующий вариант запроса будет неоптимальным (листинг 4.16).

Листинг 4.16. Вывод документов «Поступление товаров» с отбором по складу – неправильный вариант

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

(листинг 4.17).

Листинг 4.17. Вывод документов «Поступление товаров» с отбором по складу – правильный вариант

Этот вариант запроса оптимальнее, так как вся нужная информация уже есть в таблице документа.

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

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

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

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

Поэтому нежелательно обращаться к реквизитам регистратора регистра (например,

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

Например, поле Регистратор регистра ТоварыНаСкладах имеет тип ссылки на любой документ. При выполнении следующего запроса будет выполнено соединение с таблицами всех документов, имеющихся в конфигурации (листинг 4.18).

Листинг 4.18. Получение реквизитов регистратора из регистра накопления – неправильный вариант

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

Например, по условию задачи нужно отобрать только движения регистра Товары на складах, произведенные документом Поступление товаров. В этом случае оптимальным будет следующий вариант (листинг 4.19).

Листинг 4.19. Получение реквизитов регистратора из регистра накопления – правильный вариант

Это позволит значительно ускорить работу запроса, ограничив количество соединений при помощи функции приведения типа ВЫРАЗИТЬ(). В данном примере компактность и универсальность кода пожертвована в пользу его производительности. Но в результате будет выполнено только одно дополнительное соединение таблицы регистра с таблицей документом Поступление товаров.

Если ограничение количества соединений в запросе таким способом некорректно, то можно рекомендовать:

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

2.Пожертвовать компактностью хранения данных ради производительности. Если в запросе требуется значение, полученное через ссылку, то как вариант это значение можно хранить непосредственно в самом объекте. Например, в реквизите регистра можно хранить дополнительную информацию о дате регистратора. Это приведет к дублированию информации и некоторому (незначительному) увеличению ее объема, но может существенно повысить производительность и стабильность работы запроса.

3.Если данный запрос является универсальным и используется в нескольких разных ситуациях (где типы ссылки могут быть разными), то можно формировать запрос динамически, подставляя в функцию ВЫРАЗИТЬ тот тип, который необходим при данных условиях. Это увеличит объем исходного кода и, возможно, сделает его менее универсальным, но может существенно повысить производительность и стабильность работы запроса.

Исключить вывод ссылочных полей в отчет

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

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

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

подробнее

О функции Представление() рассказано в разделе «Как получить текстовое представление ссылочного поля».

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

Данные для отчета получаются при выполнении следующего запроса (листинг 4.20) и выводятся затем в табличный документ.

Листинг 4.20. Запрос для получения данных

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

Втабличный документ выводятся представления ссылочного поля ТоварПредставление, а значения самой ссылки Товар помещаются в ячейку расшифровки отчета, для того чтобы затем пользователь в отчете мог открыть запись из справочника, соответствующую этому товару