Избавиться от скана таблицы в плане запроса

20.12.22

База данных - HighLoad оптимизация

Для запросов, содержащих "LIKE %СтрокаПоиска%". Справедливо для MS SQL и Postgres.

Введение

Когда в таблице мало строк, затраты на ее сканирование несущественны, а для поиска в "больших таблицах" лучше использовать индексы. Есть как минимум один класс задач, когда бинарные индексы де-факто не помогают. Поиск по условию "LIKE %СтрокаПоиска" или "LIKE %СтрокаПоиска%" фактически равносилен скану таблицы. Например, поиск по телефонным номерам, поиск по номерам документов чаще всего происходит по последним символам.

 

Одно из возможных решений (приводилось на вебинаре Виктора Богачева)

Если для колонки таблицы планируется использовать поиск с условием "LIKE %СтрокаПоиска1", то нужно создать вспомогательную колонку, содержащую "инвертированные" данные исходной колонки. Вспомогательную колонку индексировать. Поиск производить по "инвертированному" значению, при этом условие поиска примет вид "LIKE СтрокаПоиска2%". Например, если СтрокаПоиска1 = "56789", то СтрокаПоиска2 = "98765".

 

Конкретный пример

Обратились пользователи: форма поиска контрагентов работает о-о-очень медленно. Всегда используется условие «LIKE %Строка поиска%» (провоцирует сканирование) для заполненных полей.

 

 

"Универсальную" кнопку переделал в список условий поиска, которые используют индекс. Медленную процедуру оставил для совместимости.

 

 

Пользователю необходимо одновременно искать контрагента по контактным данным, контактным данным партнера, контактным лицам. Это разные таблицы СУБД, кроме номеров телефона они содержат другую информацию. Один и тот же номер телефона может быть записан в разных форматах, расстановка символов "(, ), -, +" изменяется. По описанным причинам, индекс полнотекстового поиска не подходит. К тому же бинарный индекс занимает меньше места.

Почему выбраны последние цифры телефона? Например, выдуманный телефон 5-67-89, из соседнего села 8(243)56-789, из соседней области +7(395243)56-789, (моя малая Родина - привет землякам!) из соседней страны еще более сложный, но оканчивается также. Именно поэтому используют поиск телефона по последним цифрам. В СУБД поиск с условием «LIKE %56789» вызовет по факту сканирование таблицы, скорость О(N). Используем один из вариантов решения, разбиравшийся на вебинара Виктора Богачева вспомогательный регистр МОЙ_ПоискТелефонов, хранит "инвертированные" номера контрагентов. Измерения - "ОбратныйНомер, ВладелецТелефона". Регистр заполняется по существующим номерам и обновляется при изменении телефонов из форм справочников Контрагенты, Партнеры, Контактные лица. Например: для телефона +8(395243)56-789 храним в таблице номер 987653425938. При поиске телефона переворачиваем его, убираем нечисловые символы. Ищем с условием «LIKE 98765%». Значение 98765 находится по бинарному индексу, скорость О(logN). Если в таблице N=1024 записей, то logN = 10, ускорение в сто раз.

 

Заключение

Помните, что поиск по условию «LIKE %Строка поиска» (равносильно сканированию) всегда можно привести к поиску по условию «LIKE Строка поиска%» (использует индекс). Решения для «LIKE %Строка поиска%» также существуют и на вебинаре также рассматриваются.

 
 Приложение
 
 Правообладателям

 

Вступайте в нашу телеграмм-группу Инфостарт

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта 1С:Предприятие 8 Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

16500 руб.

02.09.2020    249813    1387    421    

1141

Инструментарий разработчика Запросы Программист 1С:Предприятие 8 1С:Зарплата и кадры государственного учреждения 3 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

QueryConsole1C — расширение, включающее консоль запросов с поддержкой исполняемых представлений — аналогов виртуальных таблиц, основанных на методах программного интерфейса ЗУП. Оно позволяет выполнять запросы с учётом встроенной бизнес-логики, отлаживать алгоритмы получения данных и автоматически генерировать код на встроенном языке 1С.

1 стартмани

16.05.2025    10238    140    zup_dev    30    

82

Запросы Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

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

11.10.2024    17002    XilDen    39    

111

HighLoad оптимизация Инструменты администратора БД Системный администратор Программист 1С 8.3 Абонемент ($m)

Обработка для простого и удобного анализа настроек, нагрузки и проблем с SQL сервером с упором на использование оного для 1С. Анализ текущих запросов на sql, ожиданий, конвертация запроса в 1С и рекомендации, где может тормозить.

5 стартмани

15.02.2024    21303    373    ZAOSTG    106    

129

HighLoad оптимизация Программист 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)

Встал вопрос: как быстро удалить строки из ТЗ? Рассмотрел пять вариантов реализации этой задачи. Сравнил их друг с другом на разных объёмах данных с разным процентом удаляемых строк. Также сравнил с выгрузкой с отбором по структуре.

09.01.2024    40327    doom2good    50    

79

HighLoad оптимизация Системный администратор Программист Бесплатно (free)

При переводе типовой конфигурации 1C ERP/УТ/КА на PostgreSQL придется вложить ресурсы в доработку и оптимизацию запросов. Расскажем, на что обратить внимание при потерях производительности и какие инструменты/подходы помогут расследовать проблемы после перехода.

20.11.2023    22209    ivanov660    7    

84

HighLoad оптимизация Бесплатно (free)

Казалось бы, КОРП-системы должны быть устойчивы, быстры и надёжны. Но, работая в рамках РКЛ, мы видим немного другую картину. Об основных болевых точках КОРП-систем и подходах к их решению пойдет речь в статье.

15.11.2023    12113    a.doroshkevich    23    

78

HighLoad оптимизация Запросы

Очень немногие из тех, кто занимается поддержкой MS SQL, работают с хранилищем запросов. А ведь хранилище запросов – это очень удобный, мощный и, главное, бесплатный инструмент, позволяющий быстро найти и локализовать проблему производительности и потребления ресурсов запросами. В статье расскажем о том, как использовать хранилище запросов в MS SQL и какие плюсы и минусы у него есть.

11.10.2023    25038    skovpin_sa    15    

106
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. SerVer1C 1061 20.12.22 13:31 Сейчас в теме
Вы рассмотрели частный случай решения проблемы, по сути, только для номеров телефонов. Не вижу решения <Для запросов, содержащих "LIKE %СтрокаПоиска%".>
artbear; lunjio; improg; t278; +4 Ответить
2. vasilev2015 2844 20.12.22 14:34 Сейчас в теме
(1) Здравствуйте !

Да, в заключении так и написано :-))
Красивое решение для случая "LIKE %СтрокаПоиска" и надежда на лучшее.
Иногда недосказанность...
it_depDi; +1 Ответить
5. RustIG 1944 20.12.22 19:10 Сейчас в теме
(2) есть задача сравнения двух таблиц в запросе по строковому полю разной длины, к примеру в одной таблице длина строки 11 символов, в другой - неогр. число символов.
но мы знаем в таблицах эти поля одинаковые.
в запросе я пробовал сравнивать (соединять) таблицы по полю, но получалось что строки "123________" <>"123____неогран"
3. RustIG 1944 20.12.22 19:06 Сейчас в теме
(1) полагаю, что "%СтрокаПоиска%" = "СтрокаПоиска%" + "ИнвертированнаяСтрокаПоиска%"
4. SerVer1C 1061 20.12.22 19:08 Сейчас в теме
(3) Но вхождение в середине строки вы всё равно быстро не найдёте
6. RustIG 1944 20.12.22 19:14 Сейчас в теме
(4) полагаю, что найду!
"СтрокаПоиска%" ищется по исходной таблице
"ИнвертированнаяСтрокаПоиска%" по вспомогательной
собираем информацию из обоих поисков
7. SerVer1C 1061 20.12.22 19:24 Сейчас в теме
(6) Эти 2 поиска будут от начала строки. Подобное "1111111СтрокаПоиска1111111" пролетает...
8. RustIG 1944 20.12.22 19:27 Сейчас в теме
(7) не понимаю, почему пролетает сама строка поиска в первом случае 12345, в инвертированном виде это 54321
10. SerVer1C 1061 20.12.22 19:30 Сейчас в теме
(8) Есть контора с названием "МирТрудМай", вы делаете поиск по "%Труд%" - как ни верти это, в индекс вы никак не попадете.
12. RustIG 1944 20.12.22 19:33 Сейчас в теме
(10) найдется одно значение ТрудМай в исходной таблице, и в вспомоагтельной "дурТриМ"
14. SerVer1C 1061 20.12.22 20:00 Сейчас в теме
(12) Чтобы не быть голословным, смотрите набросок:
В таблице одна запись "МирТрудМай", есть 1 индекс по полю "Name"
Обратите внимание, 2-й запрос вернул 1 запись, но не юзал индекс
3-й запрос вернул 0 записей, но искал по индексу.
Прикрепленные файлы:
15. RustIG 1944 20.12.22 20:06 Сейчас в теме
(14)какой у вас запрос? пришлите все запросы...
18. vasilev2015 2844 20.12.22 20:44 Сейчас в теме
(14) Сергей, Вы изучаете теорию, или у Вас есть практическая задача, которую нужно решить ?
9. RustIG 1944 20.12.22 19:29 Сейчас в теме
по исходной таблице 1112311 ищем по номеру 123%
вспог. таблица будет иметь 1132111 - по ней ищем номер 321%
13. SerVer1C 1061 20.12.22 19:48 Сейчас в теме
(9) Вот как раз здесь в обоих случаях ничего не найдётся. Знак % означает любое кол-во любых символов.
16. RustIG 1944 20.12.22 20:09 Сейчас в теме
(13) почему не найдется? Это те же две задачи что и публикации... Произойдёт бинарный поиск по двум таблицам. По очереди, сначала ищем в одной таблице, далее ищем по второму запросу из второй таблице
17. SerVer1C 1061 20.12.22 20:12 Сейчас в теме
19. RustIG 1944 20.12.22 21:47 Сейчас в теме
(17) не, запросы в виде текста надо мне
я за 10 лет вот этой вещью, которую вы мне прислали - ни разу не воспользовался, я даже не знаю что это
у вас в исходной таблице поле не проиндексировано наверное - поэтому ноль записей возвращено в третьем запросе
остальное мне непонятно
11. RustIG 1944 20.12.22 19:31 Сейчас в теме
при этом одну таблицу - полагаю, что вспомогательную - делаем базой для поиска
то есть найденные ссылки выгружаем в массив, и уже накладываем отбор на исходную таблицу по данному массиву + подобие СтрокаПоиска%
20. siamagic 21.12.22 08:22 Сейчас в теме
Почему бы просто не хранить данные в нормальном виде вместо этих глупостей?

Если хотите глупостей то ещё на 8.0 когда не было автоподбора, делали 6 колонок дополнительных в которые пихали данные из искомого по размеру.
Neuroproton; RustIG; +2 Ответить
21. vasilev2015 2844 21.12.22 08:54 Сейчас в теме
(20) зачастую дополнительная аналитика помогает избежать поиска по содержанию строк, это факт.
А для телефонных номеров лучше сделать, как описано в статье.
23. siamagic 21.12.22 10:52 Сейчас в теме
(21) Это не аналитика.
"+8(395243)56-789 храним в таблице номер 987653425938" Пользователь наберет +7 и не найдет?
24. vasilev2015 2844 21.12.22 12:00 Сейчас в теме
(23) Да, это не аналитика.
Яркий пример когда нужно использовать аналитику - строка в комментарии документа
Контрагент = Иванов, Дата отгрузки = 01/01/2023, Адрес доставки = ....

Да, строку "+7" пользователь не найдет.
Миллиард телефонных номеров как результат поиска - кому нужен ?
При поиске пользователя предупреждаем, что поиск по последним цифрам.
Смотрите картинку в статье - форма поиска.

Вариант записи номера через семерку можно предусмотреть, но у меня это не реализовано.
25. siamagic 21.12.22 12:53 Сейчас в теме
(24)
+7 имелось в виду +8(395243)56-789 тоже самое что +7(395243)56-789

"При поиске пользователя предупреждаем, что поиск по последним цифрам"
Где такое? прям вижу как в ретейле говорят покупателю назовите последние 7 цифр телефона.
Если номер из заявки в этой же ИС то нафига это всё?
Если телефонов миллиард, то вы сильно удивитесь размеру индекса + доп колонка.

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

А в реальности было бы как я сказал - формализованный телефон и полному полнотекстовый.
22. TMV 2 21.12.22 09:03 Сейчас в теме
Кажется, это имеет смысл только для данных, где большинство значений начинаются с одинаковых символов.
26. Gilev.Vyacheslav 1922 21.12.22 18:32 Сейчас в теме
есть ещё один вариант решения задачи - хранить ключ поиска - найденный ответ в отдельную табличку, переодически ее обновляя, и прежде чем делать поиск смотреть туда и сначала показывать "старый вариант" найденного, для неинтенсивно обновляемых строк и повторяющихся ключей поиска это может быть более полезно, так как отрисовка будет "сразу" (только конечно надо показывать что это из кэша и на какой момент времени) кроме того, не будет дублироваться одинаковый поиск для разных пользователей
понятно, что у того решения есть ограничения по эксплуатации
27. ivanov660 4962 21.12.22 23:55 Сейчас в теме
А что на счет механизма полнотекстового поиска? Как он работает в сравнении с вариантом запроса в СУБД?
28. vasilev2015 2844 22.12.22 11:21 Сейчас в теме
(27) Здравствуйте, Владимир !

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

Например, для номера 123456789
-бинарный индекс в этом методе содержит одну запись 987654321,
которая однозначно позиционирует результат поиска (по последним ХХ цифрам)
-полнотекстовый индекс содержит несколько записей:
пары 12; 23; 34; 45; 56; 67; 78; 89 или тройки 123; 234; 345; 456; 567; 678; 789
которые не дают однозначного ответа.
29. ivanov660 4962 22.12.22 12:07 Сейчас в теме
(28) Просто так не соглашусь. Чтобы оценить кто выигрывает, то тут требуется сравнить. К примеру:

Полнотекстовый поиск | Инвертированная колонка + запрос | Критерий
+ | - | Работает из коробки
+ | - | Поддерживает нечеткий поиск
+ | +/- | Для одного узкого случая
- | + | Стабильно работает
? | ? | Быстродействие
... | ... | Другое
30. vasilev2015 2844 22.12.22 12:14 Сейчас в теме
(29) основательный подход ))
31. Dach 390 22.12.22 23:45 Сейчас в теме
(0) решение оригинальное, но не универсальное
проблема такого поиска отлична решается колоночными СУБД
экспортим нужную информацию в тот же ClickHouse, возвращаем список уидов, подходящий текущему like и по нему уже ищем нужные строки в родной БД
32. paulwist 07.11.23 12:53 Сейчас в теме
Офигеть, тред про SARG-предикаты :))

Даю "наводку", для like '%....%' надо использовать BIN2 индексы, например, COLLATE Latin1_General_100_Bin2 - от сканирования такого индекса не избавиться, но сканирование BIN2 индекса на порядок, а иногда на 2 порядка быстрее чем сканирование просто индекса по полю. :)
Для отправки сообщения требуется регистрация/авторизация