При разработке отчетов и обработок часто возникает задача найти данные по фрагменту строки, который вводит пользователь. Начинающие разработчики нередко сталкиваются с ошибками синтаксиса, пытаясь поместить имя параметра прямо внутрь строкового литерала, например: ПОДОБНО "%[&Текст]%". Разберем по шагам, почему такая конструкция не работает, как правильно сформировать шаблон поиска и какие нюансы следует учитывать для обеспечения максимального быстродействия запроса.
В языке запросов 1С литерал строки заключается в двойные кавычки. Если поместить конструкцию &Текст внутрь кавычек, транслятор запросов воспримет ее не как параметр, а как обычный статичный текст: знак процента, открывающуюся квадратную скобку, амперсанд, слово «Текст», закрывающуюся скобку и второй знак процента. В результате запрос будет искать буквальное совпадение с этой строкой, а не с тем значением, которое передал пользователь.
Оператор ПОДОБНО сравнивает строковое поле с шаблоном. В шаблоне используются следующие управляющие знаки:
Для подстановки пользовательского значения параметр должен быть отдельной сущностью, сцепленной с символами маски поиска.
Рассмотрим вариант, когда шаблон формируется прямо в секции условий запроса с помощью оператора сложения строк +. В этом случае символы маски берутся в кавычки, а имя параметра указывается без кавычек:
ВЫБРАТЬ
Автомобили.Значение КАК Значение,
РеализацияТоваровУслуг.Ссылка КАК Ссылка
ИЗ
РегистрСведений.Автомобили КАК Автомобили
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ПО Автомобили.Автомобиль = РеализацияТоваровУслуг.Автомобиль
ГДЕ
Автомобили.ВидЗначения = &ГосНомер
И Автомобили.Значение ПОДОБНО "%" + &Текст + "%"
Этот вариант нагляден, однако у него есть недостаток: конкатенация строк переносится в план выполнения запроса на стороне СУБД, что может слегка усложнить оптимизацию плана SQL.
Проанализируем более эффективный и надежный способ. Лучшей практикой в разработке на платформе 1С считается вычисление полного шаблона поиска на стороне встроенного языка 1С до передачи в запрос. Это упрощает текст запроса и снижает нагрузку на СУБД.
Посмотрим на пример подготовки кода:
// Формируем строку шаблона во встроенном языке
ШаблонПоиска = "%" + СокрЛП(ТекстПользователя) + "%";
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Автомобили.Значение КАК Значение,
| РеализацияТоваровУслуг.Ссылка КАК Ссылка
|ИЗ
| РегистрСведений.Автомобили КАК Автомобили
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
| ПО Автомобили.Автомобиль = РеализацияТоваровУслуг.Автомобиль
|ГДЕ
| Автомобили.ВидЗначения = &ГосНомер
| И Автомобили.Значение ПОДОБНО &ШаблонПоиска";
Запрос.УстановитьПараметр("ГосНомер", ВидЗначенияГосНомер);
Запрос.УстановитьПараметр("ШаблонПоиска", ШаблонПоиска);
Результат = Запрос.Выполнить();
Обратим внимание на частую ошибку в условиях: использование конструкции вида Автомобили.Автомобиль = РеализацияТоваровУслуг.Автомобиль.Ссылка или Автомобили.ВидЗначения.Ссылка = &ГосНомер.
В платформе 1С реквизит Автомобиль уже хранит ссылку. Обращение через точку к свойству .Ссылка у ссылочного поля приводит к неявному разыменованию — генератор запросов 1С добавит в SQL-запрос дополнительное левое соединение (LEFT JOIN) с таблицей справочника ради получения той же самой ссылки. Сравнивайте ссылочные поля напрямую: Автомобили.ВидЗначения = &ГосНомер.
Оператор ПОДОБНО может быть применен только к строковым данным. Если поле в базе данных имеет составной тип (например, строка, число или ссылка), выполнение запроса завершится ошибкой или вернет некорректный результат.
Если поле составное, необходимо обязательно ограничить тип и длину:
ГДЕ ТИПЗНАЧЕНИЯ(Автомобили.Значение) = ТИП(Строка).ВЫРАЗИТЬ:
И ВЫРАЗИТЬ(Автомобили.Значение КАК Строка(150)) ПОДОБНО &ШаблонПоиска
Помните, что поиск по строкам неограниченной длины существенно замедляет выполнение запроса на уровне СУБД, поэтому рекомендуется всегда приводить их к фиксированной длине.
Если пользователь введет в строку поиска символ процента %, подчеркивание _ или квадратную скобку [, платформа воспримет их как маску шаблона. Чтобы выполнить поиск именно этих символов как обычного текста, используйте конструкцию СПЕЦСИМВОЛ:
// В запросе указывается символ экранирования, например обратный слэш:
И Автомобили.Значение ПОДОБНО &ШаблонПоиска СПЕЦСИМВОЛ "\"
Во встроенном языке перед передачей строки в параметр необходимо предварительно заменить служебные символы, добавив перед ними символ экранирования:
Текст = СтрЗаменить(ТекстПользователя, "\", "\\");
Текст = СтрЗаменить(Текст, "%", "\%");
Текст = СтрЗаменить(Текст, "_", "\_");
ШаблонПоиска = "%" + Текст + "%";
Посмотрим, как оператор ПОДОБНО влияет на работу СУБД. Наличие знака % в самом начале шаблона ("%Текст%") делает условие неселективным для индексов (Non-SARGable). СУБД физически не может применить индекс по строковому полю и будет вынуждена сканировать всю таблицу целиком (Table Scan или Index Scan). На больших таблицах это приводит к медленной работе запроса и избыточным блокировкам.
Если по бизнес-требованиям допустимо искать данные только с начала строки, всегда формируйте шаблон как Текст + "%". В этом случае СУБД выполнит эффективный поиск по индексу (Index Seek).
Если же требуется частый полнотекстовый поиск по фрагментам в больших объемах данных, оптимальнее использовать встроенный в платформу механизм полнотекстового поиска (объект ПолнотекстовыйПоиск) либо создавать специальные регистры поиска со словами фиксированной длины.