Исправления медленных запросов в 1С
Основными причинами медленно работающего запроса являются:
- > Неактуальная статистика. Если у СУБД неактуальная статистика, то оптимизатор может ошибиться при выборе оптимальной операции для получения данных, в результате чего запрос может сильно замедлиться. Например, из-за неактуальной статистики СУБД посчитала, что вернется 100 строк, и выбрала операцию сканирования, а на самом деле вернулся 1 млн строк, и в результате вместо 0,5 с запрос выполнялся 10 с, что существенно снизило производительность. Всегда важно, чтобы статистика была актуальной.
- > Плохо написанный запрос. В самом тексте запроса, приходящем в оптимизатор СУБД, уже могут быть допущены ошибки, приводящие к его медленной работе. Например, не указаны условия отбора, в результате чего выборка происходила сканированием.
- > Отсутствие подходящих индексов. Даже отлично написанный запрос не сможет увеличить скорость работы запроса так, как это может сделать наличие подходящих индексов. Если запрос вначале быстро выполняется, то из-за проблем с неиспользованием индексов со временем производительность его будет уменьшаться, т.к. будет расти количество обрабатываемых запросом данных.
Ваша 1С медленно формирует отчеты, тормозит и зависает, мы поможем решить эту проблему, обращайтесь [email protected]
Признаки неоптимального плана запроса
Рассмотрим основные признаки неоптимального плана запроса. Какие основные операции, присутствующие в плане запроса, указывают на его возможную неоптимальность.
- > Nested Loops — означает операцию соединения вложенными циклами. Принцип работы вложенных циклов: это самый простейший способ соединения двух таблиц — когда перебираются записи первой таблицы и для каждой ее записи делается перебор записей второй таблицы на выполнение условия соединения. Nested Loops как способ соединения двух таблиц хорош, если ведущая таблица содержит мало данных (1-3 строки), в других случаях предпочтительны другие способы соединения.
- > Операции сканирования (Table Scan Index Scan Clustered Index Scan) — означают полный перебор данных таблицы или индекса. Сканирование хорошо, когда сканируемая таблица содержит мало записей либо сканируется большая таблица, но из нее возвращается значительное количество данных. Если сканируется большая таблица, а возвращается небольшое количество данных, то это считается неоптимальностью — здесь лучше бы было искать данные по индексу.
- > Index Seek …Where — означает сканирование не всего индекса, а его части. То есть сначала идет выборка данных по индексу, а оставшаяся часть сканируется по определенному условию. В принципе наличие этой операции всегда указывает на неоптимальность, а именно на отсутствие подходящего индекса, будет только отличаться степень этой неоптимальности (количество сканируемых данных).
Как получить планы запросов в SQL Profiler
Чтобы получить планы запросов в SQL Profiler, необходимо выполнить следующие шаги:
Шаг 1. Запуск SQL Profiler
«Пуск — Все программы — Microsoft SQL Server — Средства обеспечения производительности — SQL Server Profiler*.
Шаг 2. Создание новой трассировки
Чтобы начать работу с SQL Profiler, необходимо выбрать меню «Файл — Создать трассировку». Прежде чем использовать SQL Profiler для решения задач, мы должны войти в SQL Server, чтобы убедиться, что у нас есть соответствующие права.
Шаг 3. Установка свойства трассировки
Нажав на кнопку «Соединить», открываем окно «Свойства трассировки». Первое, что необходимо сделать для настройки трассировки, — это задать «Имя трассировки» на закладке «Общие». Желательно, чтобы оно отражало суть тех данных, которые мы хотим собрать с помощью трассировки.
На закладке «Выбор событий» для получения плана запроса нас будут интересовать следующие события (см. рис. 1):
- > Performance\Showplan Statistics Profile. Получение текстового представления плана запроса
- > Performance\Showplan XML. Получение графического представления плана запроса
- > Stored Procedures\RPC:Completed. Получение запроса, выполняемого хранимой процедурой
- > TSQL\SQL:BatchCompleted. Получение запроса, выполняемого как обычный запрос

Шаг 4. Установка фильтров
Часто необходимо собрать информацию о конкретном событии, но только при наступлении определенных условий. Например, события определенного пользователя или для определенной базы данных. Фильтры позволяют отобрать те события, которые нас интересуют.
При нажатии на кнопку «Фильтры столбцов» на закладке «Выбор событий» окна «Свойства файла трассировки» откроется окно «Изменение фильтра», в котором мы обязательно должны установить следующие отборы:
- > Отбор на столбец DatabaseName. Здесь мы ставим фильтр на имя базы данных, в которой мы хотим найти медленные запросы. Если мы не установим отбор на базу данных, то к нам в трассировку будут попадать все запросы по всем базам данных, находящимся на данном SQL Server (см. рис. 2).

- > Отбор на столбец Duration. Здесь мы ставим фильтр, чтобы получать только те запросы, которые выполнялись более 1 мс (см. рис. 3).

Шаг 5. Запуск, сбор данных и остановка трассировки
После того как свойства файла трассировки установлены, нажимаем кнопку «Запустить» в нижнем правом углу интерфейса.
Сейчас рассмотрим основные приемы работы с трассировкой (запуск, пауза, остановка и т.д.).
- > Старт трассировки. После нажатия нами кнопки «Запустить» уже начали собираться данные в трассировку (см. рис. 4). Экран сбора трассировки разделен на две части: в верхней части содержится список событий, а нижняя часть показывает содержимое поля TextData. В нижней левой части окна выдается сообщение

«Трассировка выполняется», которая показывает текущее состояние трассировки. Другие сообщения, которые могут выводиться: «Трассировка приостановлена», «Трассировка остановлена». В нижней правой части окна показываются номер текущей строки и номер текущего столбца, на котором остановлен курсор, а также общее количество строк.
Приостановка трассировки. Мы можем приостановить сбор трассировки для того, чтобы в дальнейшем продолжить ее сбор. Для этого на панели необходимо нажать кнопку «Пауза».
Остановка трассировки. Чтобы остановить сбор данных трассировкой, необходимо нажать на кнопку «Стоп» на панели.
Очистка трассировки. Если мы сохранили данные трассировки и собранные данные нам уже не понадобятся, то мы можем очистить оперативную память от собранных данных. Для этого необходимо на панели нажать кнопку «Очистить трассировку»
Шаг 6. Сохранение файла трассировки
Сохранение данных трассировки в файл может понадобиться в очень многих случаях. Например, у вас нет времени именно сейчас расследовать причину либо собранные данные необходимо отправить другому человеку для дальнейшего анализа.
Файл трассировки можно сохранить в формате .trc. Для этого необходимо просто остановить трассировку и выбрать пункт меню «Файл — Сохранить как — Файл трассировки».
Поиск плана запроса для медленных запросов
После завершения сбора данных трассировки необходимо ее проанализировать. Если трассировка небольшая по размеру, то можно ее посмотреть вручную. Для этого необходимо смотреть строки с большим временем выполнения (Duration) и большим количеством чтений (Reads). План запроса для выделенной строки будет находиться над соответствующей строкой с текстом запроса (см. рис. 5).

Анализ полученного плана запроса
Найденный план запроса необходимо проверить на признаки неоптимальности, а точнее, на наличие операций сканирования, вложенных циклов, поиск индекса по неполному условию.
Проверка плана запроса на признаки неоптимальности
В данном плане запроса присутствуют вложенные циклы, что является подозрением на причину медленной работы. Но если присмотреться к этой операции плана запроса (см. рис. 6), то можно увидеть, что она занимает только 10% от всего времени выполнения запроса. И если навести курсор на входящую стрелочку, то видно, что ведущая таблица содержит мало данных (предполагаемое количество равно 1, а фактическое равно 0), поэтому вложенные циклы в данном плане запроса не являются проблемой.
Следующим подозрительным элементом плана запроса является операция поиска по индексу Clustered Index Seek (см. рис. 6). Эта операция означает, что происходил поиск по кластерному индексу. Поиск по индексу является «хорошей» операцией, но т.к. вес времени выполнения всего запроса очень высок (76%), то нужно проверить ее на дополнительное сканирование (Index Seek .. .Where).
Для того чтобы проверить операцию на дополнительное сканирование, мы можем навести курсор на данную операцию и посмотреть во всплывающей подсказке, есть ли блок «Предикат», — это и будет условием дополнительного сканирования (см. рис. 7).
Нахождение неоптимального запроса в коде конфигурации 1С
Получив информацию о соответствии метаданных 1С, с помощью поиска в конфигураторе 1С можем найти нужный запрос (см. листинг 1).
Запрос.Текст = »
|ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура ↵
КАК Номенклатура,
| СУММА(НеобходимыеТовары.Количество) КАК Необходимо,
| СУММА(ТоварыНаСкладахОстатки.КоличествоОстаток) ↵
КАК Остаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| ,
| (Склад, Номенклатура) В
| (ВЫБРАТЬ РАЗЛИЧНЫЕ
| Документ.Реализация.Товары.Склад,
| Документ.Реализация.Товары.Номенклатура
| ИЗ
| Документ.Реализация.Товары
| ГДЕ
| Документ.Реализация.Товары.Ссылка = ↵
&Документ)) ↵
КАК ТоварыНаСкладахОстатки
|
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.Реализация.Товары ↵
КАК НеобходимыеТовары
| ПО НеобходимыеТовары.Ссылка = &Документ
| И НеобходимыеТовары.Номенклатура = ↵
ТоварыНаСкладахОстатки.Номенклатура
|
|СГРУППИРОВАТЬ ПО
| ТоварыНаСкладахОстатки.Номенклатура»;
Исправление плохого запроса
Исходя из текста запроса, структуры метаданных и плана запроса можно сделать вывод, что в запросе используется одновременно условие по полям «Склад» и «Номенклатура», а в индексе данной таблицы поля идут следующим образом: «Склад», «Характеристика», «Номенклатура», т.е. из-за разрыва полей в условии СУБД пришлось прибегнуть к дополнительному сканированию по полю «Номенклатура».
alt=»profiler-7″ width=»300″ height=»59″ />
Чтобы исправить работы этого запроса, мы изменим порядок полей индекса данной таблицы. Для этого в конфигураторе 1С поменяем местами порядок следования измерений «Номенклатура» и «Харакеристика» в регистре накопления «ТоварыНаСкладах» (см. рис. 9).

Важно помнить, что, исправив что-то в одном месте, можно ухудшить ситуацию с производительностью в другом месте.
Проверка полученных результатов
После исправления и запуска трассировки заново можно увидеть, что время выполнения запроса уменьшилось в пять раз (с 10 до 2 мс) и дополнительное сканирование по полю [AccumRgT11].[_Fld8RRef] тоже исчезло.
Анализ большой трассировки. Сохранение трассировки в таблицу
Когда собранных данных в трассировке много, то искать медленные запросы вручную тяжело. Рассмотрим последовательность действий для нахождения медленных запросов.
Выгрузить полученную трассировку в таблицу
Чтобы сохранить трассировку в таблицу SQL Server надо:
- > Выбрать «Файл — Сохранить как — Таблица трассировки».
- > В открывшемся меню выбрать базу данных и название таблицы, в которую будет сохранена трассировка. Если работаете на тестовом оборудовании и работа носит разовый характер, то можно пользоваться базой данных master, но лучше создать отдельную базу данных для этих целей. В данном случае мы создадим таблицу PF2016 в базе данных master.
Получить запросы с максимальным временем
Для этого мы должны открыть Microsoft SQL Server Management Studio и создать новый запрос (см. листинг 2).
Листинг 2. Получение списка самых медленных запросов
SELECT [RowNumber]
,[Duration]/1000 AS Duration ,[Reads] ,[TextData] FROM [master].[dbo].[PF2016] Order by [Duration] desc
В результате мы получим отсортированный по убыванию список самых медленных запросов (см. рис. 10).
Чтобы найти соответствующий запросу план, нам необходимо найти этот же запрос в файле трассировки. Зная значение номера строки (RowNumber) из полученного запроса, в окне трассировки выберем «Правка — Перейти к» (<Ctrl> + <G>), перейдем к соответствующему номеру строки, а план запроса будет располагаться выше этой позиции.
Список основных причин медленной работы запросов 1С
Часто, глядя прямо на код запроса в 1С, можно понять причину его медленной работы. К основным причинам медленной работы относятся:
- > Соединения подзапросами или виртуальными таблицами. Приводит к использованию Nested Loops.
Решение: переписать запрос с использованием временных таблиц.
- > Несоответствие индексов и условий запроса. Приводит к операциям сканирования.
Решение : переписать текст запроса или создать подходящий индекс.
- > Неиспользование параметров виртуальных таблиц 1С. Приводит к неиспользованию индекса и, как следствие, к сканированию.
Решение: использовать параметры виртуальных таблиц.
- > Получение данных через точку от полей составного типа. Приводит к усложнению текста запроса, т.к. СУБД приходится делать соединение со всеми таблицами, входящими в это составное поле.
Решение: использование «Выразить» для ограничения количества таблиц или не использовать получение данных через точку.
- > Использование логического «ИЛИ» в условии. Использование «ИЛИ» в условии может привести к неиспользованию индекса.
Решение: заменить текст запроса на два отдельных с объединением результатов.
Использование SQL Profiler может серьезно помочь в поиске, анализе и исправлении медленно работающих запросов 1С. Важно научиться грамотно работать с этим инструментом оптимизации.
Графический план выполнения запроса 1С

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "///// echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1.
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.
Собственно сам скрипт:
<?php // Полная загрузка сервисных книжек, создан 2023-01-05 12:44:55
global $wpdb2;
global $failure;
global $file_hist;
$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once ‘connection.php’; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
<
///// echo ‘<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>’;
$failure=TRUE;
wp_die( $wpdb2->error );
>
$m_size_file=0;
$m_mtime_file=0;
$m_comment=»;
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.’/_1c_alfa_exchange/AA_hist.csv’;
if (!file_exists($file_hist))
<
///// echo ‘<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>’;
$m_comment=’Файл обмена с сервисными книжками не существует’;
$failure=TRUE;
>
/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure) <
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET[‘foo’]
///// echo ‘<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>’;
$insert_fail_zapros=$wpdb2->insert(‘vin_logs’, array(‘time_stamp’=>time(),’last_mtime_upload’=>$m_mtime_file,’last_size_upload’=>$m_size_file,’comment’=>$m_comment));
wp_die();
///// echo ‘<H2><b>Возврат в начало.</b></H2><br>’;
return $failure;
>
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist); ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7]; ////получаем размер файла
$m_mtime_file=$masiv_data_file[9]; ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file
///// echo ‘<H2><b>Размер файла: ‘.$m_size_file.'</b></H2><br>’;
///// echo ‘<H2><b>Штамп времени файла: ‘.$m_mtime_file.'</b></H2><br>’;
///// echo ‘<H2><b>Формирование запроса на выборку из лога</b></H2><br>’;
////препарируем запрос
$text_zaprosa=$wpdb2->prepare(«SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s», $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);
if ($results)
< foreach ( $results as $r)
<
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
///echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert(‘vin_logs’, array(‘time_stamp’=>time(),’last_mtime_upload’=>$m_mtime_file,’last_size_upload’=>$m_size_file,’comment’=>’Загрузка отменена, новых данных нет, т.к. найдена запись в логе.’));
wp_die();
return $failure;
>
>
>
////если данные новые, пишем в лог запись о начале загрузки
/////echo ‘<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>’;
$insert_fail_zapros=$wpdb2->insert(‘vin_logs’, array(‘time_stamp’=>time(),’last_mtime_upload’=>0, ‘last_size_upload’=>$m_size_file, ‘comment’=>’Начало загрузки’));
////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare(«TRUNCATE TABLE %s», ‘vin_history’);
$clear_tbl_zap_repl=str_replace(«‘»,»`»,$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
///// echo ‘<H2><b>Очистка таблицы сервисных книжек</b></H2><br>’;
if (empty($results))
<
///// echo ‘<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>’;
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
>
////загружаем данные
$table=’vin_history’; // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация // (путь от корня web-сервера)
$delim=’;’; // Разделитель полей в CSV файле
$enclosed='»‘; // Кавычки для содержимого полей
$escaped=’\
Как собирать планы запросов с фильтром по длительности?
(4)
легко может оказаться , что 1с грешит множеством мелких запросов , тогда они не попадут в фильтр по длительности.
1с ника так любят делать. например так было в закрытии периода в бухгалтерии . 1,5М мелких запросов.
(15) 3.14.1.7 Элемент plansql
Если элемент <plansql> присутствует, то будет включен сбор планов запросов, которые генерируют СУБД при выполнении запросов «1С:Предприятия». Сами планы запросов расположены в свойстве <planSQLText> событий, связанных с исполнением запросов конкретной СУБД (см. здесь).
СОВЕТ. Рекомендуется вместе со свойством <planSQLText> включать в состав регистрируемых свойств также и свойство <SQL>, содержащее запрос, план которого будет зарегистрирован.
АйТиБложик
Для формирования и выполнения запросов к таблицам базы данных в платформе 1С используется специальный объект языка программирования Запрос. Создается этот объект вызовом конструкции Новый Запрос. Запрос удобно использовать, когда требуется получить сложную выборку данных, сгруппированную и отсортированную необходимым образом. Классический пример применения запроса — получение сводки по состоянию регистра накопления на определенный момент времени. Так же, механизм запросов позволяет легко получать информацию в различных временных разрезах.
- таблицы информационной базы, используемые в качестве источников данных запроса;
- поля таблиц, которые требуется обрабатывать в запросе;
- правила группировки;
- сортировки результатов;
- и т. д.
Язык запросов платформы 1С очень похож на синтаксис других SQL-языков, но имеются отличия. Основными преимуществами встроенного языка запросов являются: разыменование полей, наличие виртуальных таблиц, удобная работа с итогами, нетипизированные поля в запросах.
- значения перечислений;
- предопределенные данные:
- справочников;
- планов видов характеристик;
- планов счетов;
- планов видов расчетов;
- пустые ссылки;
- значения точек маршрута бизнес-процессов.
Пример использования литерала ЗНАЧЕНИЕ:
—> ГДЕ Город = ЗНАЧЕНИЕ(Справочник.Города.Москва)
ГДЕ Город = ЗНАЧЕНИЕ(Справочник.Города.ПустаяСсылка)
ГДЕ ТипТовара = ЗНАЧЕНИЕ(Перечисление.ВидыТоваров.Услуга)
ГДЕ ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ГДЕ ТочкаМаршрута = ЗНАЧЕНИЕ(БизнесПроцесс.БизнесПроцесс1.ТочкаМаршрута.Действие1
- Если в запросе было указано предложение УПОРЯДОЧИТЬ ПО, то каждая ссылка на таблицу, находящаяся в этом предложении, будет заменена полями, по которым по умолчанию сортируется таблица (для справочников это код или наименование, для документов – дата документа). Если поле для упорядочивания ссылается на иерархический справочник, то будет применена иерархическая сортировка по этому справочнику.
- Если в запросе отсутствует предложение УПОРЯДОЧИТЬ ПО, но есть предложение ИТОГИ, тогда результат запроса будет упорядочен по полям, присутствующим в предложении ИТОГИ после ключевого слова ПО, в той же последовательности и, в случае если итоги рассчитывались по полям – ссылкам, то по полям сортировки по умолчанию таблиц, на которые были ссылки.
- Если в запросе отсутствуют предложения УПОРЯДОЧИТЬ ПО и ИТОГИ, но есть предложение СГРУППИРОВАТЬ ПО, тогда результат запроса будет упорядочен по полям, присутствующим в предложении, в той же последовательности и, в случае если группировка велась по полям – ссылкам, то по полям сортировки по умолчанию таблиц, на которые были ссылки.
- В случае же, если в запросе отсутствуют предложения и УПОРЯДОЧИТЬ ПО, ИТОГИ и СГРУППИРОВАТЬ ПО, результат будет упорядочен по полям сортировки по умолчанию для таблиц, из которых выбираются данные, в порядке их появления в запросе.
3) Что бы избежать повторного запроса к базе данных при выводе результата запроса пользователю (например, построение запроса или отображение результата запроса с помощью табличного документа) полезно использовать инструкцию ПРЕДСТАВЛЕНИЕССЫЛКИ, которая позволяет получать представление ссылочного значения.
Пример:
ВЫБРАТЬ
ПРЕДСТАВЛЕНИЕССЫЛКИ(РасходнаяНакладнаяСостав.Номенклатура) КАК НоменклатураПредставление
Так же возможно использование инструкции ПРЕДСТАВЛЕНИЕ — предназначена для получения строкового представления значения произвольного типа. Отличие этих инструкций в том, что в первом случае, если инструкции передать ссылку, результатом будет строка, В остальных случаях результатом будет значение переданного параметра. Во втором случае, результатом инструкции всегда будет строка!
4) Если в запросе имеется поле с составным типом, то для таких полей возникает необходимость привести значения поля к какому-либо определенному типу с помощью инструкции ВЫРАЗИТЬ, что позволит убрать лишние таблицы из левого соединения с полем составного типа данных и ускорить выполнение запроса.
Пример:
Имеется регистра накопления ОстаткиТоваров, у которого поле Регистратор имеет составной тип. В запросе выбираются Дата и Номер документов ПоступлениеТоваров, при этом при обращении к реквизитам документа через поле Регистратор не происходит множество левых соединений таблицы регистра накопления с таблицами документов-регистраторов.
ВЫБРАТЬ
ВЫРАЗИТЬ(ОстаткиТоваров.Регистратор КАК Документ.ПоступлениеТоваров).Номер КАК НомерПоступления,
ВЫРАЗИТЬ(ОстаткиТоваров.Регистратор КАК Документ.ПоступлениеТоваров).Дата КАК ДатаПоступления
ИЗ
РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваров
Если приведение типа считается не осуществимым, то результатом приведения типа будет значение NULL.
5) Не стоит забывать про инструкцию РАЗРЕШЕННЫЕ, которая означает, что запрос выберет только те записи, на которые у текущего пользователя есть права. Если данное слово не указать, то в случае, когда запрос выберет записи, на которые у пользователя нет прав, запрос отработает с ошибкой.
6) В случае, если в запросе используется объединение, и в некоторых частях объединения присутствуют вложенные таблицы (документ с табличной частью), а в некоторых нет, возникает необходимость дополнения списка выборки полями – пустыми вложенными таблицами. Делается это при помощи ключевого слова ПУСТАЯТАБЛИЦА, после которого в скобках указываются псевдонимы полей, из которых будет состоять вложенная таблица.
Пример:
// Выбрать поля Номер и Состав
// из виртуальной таблицы Документ.РасхНакл
ВЫБРАТЬ Ссылка.Номер, ПУСТАЯТАБЛИЦА.(Ном, Тов, Кол) КАК Состав
ИЗ Документ.РасхНакл
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Ссылка.Номер, Состав.(НомерСтроки, Товар, Количество)
ИЗ Документ.РасхНакл Документ.РасходнаяНакладная.Состав.*
7) Что бы в результат запроса не попали повторяющиеся строки, следует использовать инструкцию РАЗЛИЧНЫЕ, потому что так нагляднее и понятнее, а инструкция СГРУППИРОВАТЬ ПО применяется для группировки с помощью агрегатных функций. Ксати, при использовании агрегатных функций предложение СГРУППИРОВАТЬ ПО может быть и не указано совсем, при этом все результаты запроса будут сгруппированы в одну единственную строку.
Пример:
// Необходимо узнать, каким вообще контрагентам
// отгружался товар за период.
Выбрать Различные
Документ.РасходнаяНакладная.Контрагент
8) Инструкция СГРУППИРОВАТЬ ПО позволяет обращаться к полям верхнего уровня, без группировки результатов по этим полям, если агрегатные функции применены к полям вложенной таблицы. Хотя в справке 1С написано, при группировке результатов запроса в списке полей выборки обязательно должны быть указаны агрегатные функции, а помимо агрегатных функций в списке полей выборки допускается указывать только поля, по которым осуществляется группировка.
Пример:
ВЫБРАТЬ
ПоступлениеТоваровИУслуг.Товары.(СУММА(Количество),Номенклатура),
ПоступлениеТоваровИУслуг.Ссылка,
ПоступлениеТоваровИУслуг.Контрагент
ИЗ
Документ.ПоступлениеТоваровИУслуг КАК ПоступлениеТоваровИУслуг
СГРУППИРОВАТЬ ПО
ПоступлениеТоваровИУслуг.Товары.(Номенклатура)
9) Инструкция ЕСТЬNULL предназначена для замены значения NULL на другое значение, но не забываем, что второй параметр будет преобразован к типу первого в случае, если тип первого параметра является строкой или числом.
10) При обращении к главной таблице можно в условии обратиться к данным подчиненной таблицы. Такая возможность называется разыменование полей подчиненной таблицы.
Пример (поиск документов, содержащих в табличной части определенный товар):
ВЫБРАТЬ
Приходная.Ссылка
ИЗ
Документ.Приходная Где Приходная.Товары.Номенклатура = &Номенклатура.
Преимущество этого запроса перед запросом к подчиненной таблице Приходная.Товары в том, что если есть дубли в документах, результат запроса вернет только уникальные документы без использования ключевого слова РАЗЛИЧНЫЕ.
11) Интересный вариант оператора В — это проверка вхождения упорядоченного набора в множество таких наборов (Поле1, Поле2, . , ПолеN) В (Поле1, Поле2, . , ПолеN).
Пример:
ВЫБРАТЬ
Контрагенты.Ссылка
ГДЕ
(Контрагенты.Ссылка, Товары.Ссылка) В
(ВЫБРАТЬ Продажи.Покупатель, Продажи.Товар
ИЗ РегистрНакопления.Продажи КАК Продажи)
ИЗ
Справочник.Контрагенты,
Справочник.Товары
12) При любой возможности используйте виртуальные таблицы запросов. При создании запроса система предоставляет в качестве источников данных некоторое количество виртуальных таблиц — это таблицы, которые так же являются результатом запроса, который система формирует в момент выполнения соответствующего участка кода.
- Все виртуальные таблицы параметризованы, т. е. разработчику предоставляется возможность задать некоторые параметры, которые система будет использовать при формировании запроса создания виртуальной таблицы. В зависимости от того, какие параметры виртуальной таблицы указаны разработчиком, система может формировать РАЗЛИЧНЫЕ запросы для получения одной и той же виртуальной таблицы, причем они будут оптимизированы с точки зрения переданных параметров.
- Не всегда разработчик имеет возможность получить доступ к тем данным, к которым имеет доступ система.
14) С осторожностью используйте ИЛИ в конструкции ГДЕ, так как использование условия с ИЛИ может значительно «утяжелить» запрос. Решить проблему можно конструкцией ОБЪЕДИНИТЬ ВСЕ.
Пример:
ВЫБРАТЬ
_ДемоКонтрагенты.НаименованиеПолное
ИЗ
Справочник._ДемоКонтрагенты КАК _ДемоКонтрагенты
ГДЕ
_ДемоКонтрагенты.Ссылка = &Ссылка1
ВЫБРАТЬ
_ДемоКонтрагенты.НаименованиеПолное
ИЗ
Справочник._ДемоКонтрагенты КАК _ДемоКонтрагенты
ГДЕ
_ДемоКонтрагенты.Ссылка = &Ссылка2
15) Условие НЕ В в конструкции ГДЕ увеличивает время исполнения запроса, так как это своего рода НЕ (ИЛИ1 ИЛИ2 . ИЛИn), поэтому для больших таблиц старайтесь использовать ЛЕВОЕ СОЕДИНЕНИЕ с условием ЕСТЬ NULL.
Пример:
ВЫБРАТЬ
_ДемоКонтрагенты.Ссылка
ИЗ
Справочник._ДемоКонтрагенты КАК _ДемоКонтрагенты
ЛЕВОЕ СОЕДИНЕНИЕ Документ._ДемоЗаказПокупателя КАК _ДемоЗаказПокупателя
ПО _ДемоКонтрагенты.Ссылка = _ДемоЗаказПокупателя.Контрагент
ГДЕ
_ДемоЗаказПокупателя.Контрагент ЕСТЬ NULL
15) При использовании Временных таблиц нужно индексировать поля условий и соединений в этих таблицах, НО, при использовании индексов запрос может выполняться еще медленнее. Поэтому необходимо анализировать каждый запрос с применением индекса и без, замерять скорость выполнения запроса и принимать окончательное решение.
Если вы помещаете во временную таблицу данные, которые изначально индексированы по некоторым полям, то во временной таблице индекса по этим полям уже не будет.
16) Если вы не используете Менеджер временных таблиц, то явно удалять временную таблицу не требуется, она будет удалена после завершения выполнения пакетного запроса, иначе следует удалить временную таблицу одним из способов: командой УНИЧТОЖИТЬ в запросе, вызвать метод МенеджерВременныхТаблиц.Закрыть().