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

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 %Строка поиска%» также существуют и на вебинаре также рассматриваются.

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

 

См. также

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

Инструментарий разработчика Роли и права Запросы СКД Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

10000 руб.

02.09.2020    126430    683    389    

737

Анализируем SQL сервер глазами 1С-ника

HighLoad оптимизация Инструменты администратора БД Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

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

1 стартмани

15.02.2024    8413    170    ZAOSTG    74    

102

Опыт оптимизации 1С на PostgreSQL

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

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

20.11.2023    9560    ivanov660    6    

76

Начните уже использовать хранилище запросов

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

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

11.10.2023    16684    skovpin_sa    14    

101

MS SQL Server: изучаем планы запросов

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

Многие знают, что для ускорения работы запроса нужно «изучить план». При этом сам план обычно обескураживает: куча разноцветных иконок и стрелочек; ничего не понятно, но очень интересно! Аналитик производительности Александр Денисов на конференции Infostart Event 2021 Moscow Premiere рассказал, как выполняется план запроса и что нужно сделать, чтобы с его помощью находить проблемы производительности.

20.06.2023    17271    Филин    37    

114

Все консоли запросов для 1С

Запросы Инструментарий разработчика Бесплатно (free)

Список всех популярных обработок.

17.03.2023    37993    kuzyara    87    

182

Пример многопоточной обработки (БСП)

HighLoad оптимизация БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Обработка-шаблон, на основе которой можно делать свои многопоточные обработки данных для конфигураций на БСП.

13.02.2023    9529    7    echo77    8    

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

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

Если хотите глупостей то ещё на 8.0 когда не было автоподбора, делали 6 колонок дополнительных в которые пихали данные из искомого по размеру.
Neuroproton; RustIG; +2 Ответить
21. vasilev2015 2699 21.12.22 08:54 Сейчас в теме
(20) зачастую дополнительная аналитика помогает избежать поиска по содержанию строк, это факт.
А для телефонных номеров лучше сделать, как описано в статье.
23. siamagic 21.12.22 10:52 Сейчас в теме
(21) Это не аналитика.
"+8(395243)56-789 храним в таблице номер 987653425938" Пользователь наберет +7 и не найдет?
24. vasilev2015 2699 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 14 21.12.22 09:03 Сейчас в теме
Кажется, это имеет смысл только для данных, где большинство значений начинаются с одинаковых символов.
26. Gilev.Vyacheslav 1911 21.12.22 18:32 Сейчас в теме
есть ещё один вариант решения задачи - хранить ключ поиска - найденный ответ в отдельную табличку, переодически ее обновляя, и прежде чем делать поиск смотреть туда и сначала показывать "старый вариант" найденного, для неинтенсивно обновляемых строк и повторяющихся ключей поиска это может быть более полезно, так как отрисовка будет "сразу" (только конечно надо показывать что это из кэша и на какой момент времени) кроме того, не будет дублироваться одинаковый поиск для разных пользователей
понятно, что у того решения есть ограничения по эксплуатации
27. ivanov660 4347 21.12.22 23:55 Сейчас в теме
А что на счет механизма полнотекстового поиска? Как он работает в сравнении с вариантом запроса в СУБД?
28. vasilev2015 2699 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 4347 22.12.22 12:07 Сейчас в теме
(28) Просто так не соглашусь. Чтобы оценить кто выигрывает, то тут требуется сравнить. К примеру:

Полнотекстовый поиск | Инвертированная колонка + запрос | Критерий
+ | - | Работает из коробки
+ | - | Поддерживает нечеткий поиск
+ | +/- | Для одного узкого случая
- | + | Стабильно работает
? | ? | Быстродействие
... | ... | Другое
30. vasilev2015 2699 22.12.22 12:14 Сейчас в теме
(29) основательный подход ))
31. Dach 373 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 порядка быстрее чем сканирование просто индекса по полю. :)
Оставьте свое сообщение