При написании запросов в платформе 1С:Предприятие разработчики часто сталкиваются с дилеммой выбора операторов сравнения строк. На первый взгляд может показаться, что использование оператора ПОДОБНО (аналог LIKE в SQL) без использования специальных символов маски (таких как % или _) эквивалентно обычному оператору равенства =. Однако на практике эти два оператора работают на уровне СУБД совершенно по-разному. В этой статье мы подробно разберем, почему они могут возвращать разные результаты, как это влияет на производительность системы и развенчаем популярные мифы, связанные с регистрозависимостью.
Рассмотрим ситуацию, когда при поиске по строковому реквизиту один запрос с оператором = возвращает данные, а аналогичный запрос с оператором ПОДОБНО выдает пустой результат. Выясним причину этого поведения, которая кроется в стандартах работы СУБД со строковыми типами данных.
Согласно стандарту ANSI SQL-92, сравнение строк с помощью оператора равенства = происходит по особым правилам. Перед сопоставлением двух строк СУБД автоматически дополняет более короткую строку пробелами справа, чтобы их физическая длина сравнялась, и только после этого выполняет посимвольное сравнение.
Проанализируем простой пример. Допустим, мы сравниваем две строки:
"Иванов" (длина 6 символов)"Иванов " (длина 7 символов, на конце пробел)При использовании оператора равенства выражение будет обработано следующим образом:
// СУБД приводит строки к одной длине, виртуально дополняя первую пробелом:
"Иванов " = "Иванов " // Результат: ИСТИНА (True)
Теперь посмотрим, что происходит при использовании оператора ПОДОБНО. Этот оператор предназначен для поиска по шаблону, поэтому правила дополнения строк пробелами к нему не применяются. Для СУБД любой пробел в шаблоне (в правой части выражения) является значащим символом, который должен быть найден в исходной строке один в один.
// Сравнение по шаблону без автодополнения пробелами:
"Иванов" ПОДОБНО "Иванов " // Результат: ЛОЖЬ (False)
Таким образом, если пользователь при вводе поискового запроса случайно нажал клавишу пробела в конце слова, или если в самой базе данных содержатся строки с невидимыми концевыми пробелами, оператор равенства = успешно найдет соответствие, а оператор ПОДОБНО без спецсимволов вернет пустой результат. Это ключевое различие, которое напрямую влияет на корректность работы ваших алгоритмов поиска.
В платформе 1С существуют строки переменной длины и строки фиксированной длины. На уровне СУБД строки фиксированной длины хранятся в полях типа CHAR, а переменной — в полях типа VARCHAR. Поля типа CHAR всегда физически заполняются пробелами до максимального размера, указанного в метаданных.
Хотя платформа 1С берет на себя множество задач по унификации работы с СУБД, при выполнении сложных запросов (например, при соединении таблиц по строковым полям) разница в обработке типов CHAR и VARCHAR может приводить к неожиданному поведению. Оператор равенства = отрабатывает такие сравнения предсказуемо и стабильно благодаря все тому же стандарту ANSI SQL-92, в то время как поведение ПОДОБНО может сильно зависеть от конкретной СУБД и физического наполнения полей пробелами.
Рассмотрим, как выбор оператора влияет на скорость выполнения запроса оптимизатором СУБД (будь то Microsoft SQL Server, PostgreSQL, IBM DB2 или Oracle). Это критически важный аспект при работе с высоконагруженными или крупными базами данных.
В теории баз данных существует понятие SARGable (Search Argument Able) — это свойство условий в запросе, которое позволяет оптимизатору эффективно использовать существующие индексы для быстрого поиска данных.
Index Seek (поиск по индексу). Это самый быстрый способ получения данных, который работает практически мгновенно даже на таблицах с миллионами записей.ПОДОБНО "Кока-Кола"), оптимизатор запросов вынужден тратить дополнительные ресурсы на анализ строки.
ПОДОБНО "Значение" до обычного = "Значение" и построить оптимальный план запроса.Table Scan / Index Scan). Это приведет к полной вычитке данных с диска и катастрофическому падению производительности всей системы.Именно поэтому использование ПОДОБНО при соединении таблиц в условиях ПО категорически не рекомендуется стандартами разработки фирмы 1С. Соединения должны выполняться исключительно по оператору равенства =.
Среди начинающих разработчиков часто циркулирует заблуждение, что оператор ПОДОБНО позволяет выполнять регистронезависимый поиск там, где оператор равенства = якобы чувствителен к регистру. Это абсолютно неверное представление о работе СУБД.
Регистрозависимость любого сравнения строк в запросах 1С определяется исключительно настройками сортировки (Collation) базы данных в СУБД, но никак не выбранным оператором запроса.
Рассмотрим два сценария настройки базы данных:
Cyrillic_General_CI_AS, где суффикс CI расшифровывается как Case Insensitive — регистронезависимый). В такой базе данных выражения "яблоко" = "ЯБЛОКО" и "яблоко" ПОДОБНО "ЯБЛОКО" вернут одинаковый результат — ИСТИНА.=, и ПОДОБНО) будут строго требовать совпадения регистра символов. Выражение "яблоко" = "ЯБЛОКО" вернет ЛОЖЬ, равно как и выражение с оператором ПОДОБНО.Таким образом, оператор ПОДОБНО сам по себе не обладает магическим свойством игнорировать регистр символов, если это запрещено глобальными настройками базы данных.
Давайте посмотрим на живые примеры написания кода в 1С, чтобы закрепить материал и понять, как писать запросы правильно.
Представим, что перед нами стоит задача найти контрагента по его точному наименованию. Рассмотрим некорректный вариант реализации поиска:
// НЕКОРРЕКТНЫЙ ВАРИАНТ: Использование ПОДОБНО без спецсимволов
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.Наименование ПОДОБНО &Наименование";
// Если в переменной ИмяПоиска окажется лишний пробел на конце, запрос ничего не найдет
ИмяПоиска = "ООО Ромашка ";
Запрос.УстановитьПараметр("Наименование", ИмяПоиска);
Результат = Запрос.Выполнить();
А теперь напишем правильный, отказоустойчивый и максимально быстрый код с использованием оператора равенства:
// ПРАВИЛЬНЫЙ ВАРИАНТ: Использование оператора равенства
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.Наименование = &Наименование";
// Рекомендуется всегда очищать входные параметры от нежелательных пробелов с помощью функции СокрЛП()
ИмяПоиска = СокрЛП("ООО Ромашка ");
Запрос.УстановитьПараметр("Наименование", ИмяПоиска);
Результат = Запрос.Выполнить();
Подводя итог нашему анализу, можно с уверенностью сказать: использование оператора ПОДОБНО без спецсимволов не имеет никаких практических или технических преимуществ перед оператором равенства «=». Напротив, такое написание кода несет в себе скрытые риски:
Используйте оператор ПОДОБНО только по его прямому назначению — когда вам действительно требуется выполнить нечеткий поиск по маске с использованием спецсимволов % (любое количество произвольных символов) или _ (один произвольный символ). Во всех остальных случаях вашим основным инструментом всегда должен оставаться классический оператор равенства =.