Имя: Пароль:
1C
1С v8
Оптимизация скорости поиска номенклатуры запросом по наименованию.
0 Повелитель
 
07.09.16
06:56
Справочник номенклатура относительно не большой 255 000 товаров.
Заметил, что поиск по наименованию запросом составляет от 1 до 2 секунд.
Поиск производим по справочнику списку номенклатуры.

Вот запрос (время выполнения 1-2 секунды):
ВЫБРАТЬ
    мНоменклатура.Ссылка КАК Ссылка,
    мНоменклатура.Наименование КАК Номенклатура
ИЗ
    Справочник.Номенклатура КАК мНоменклатура
ГДЕ
    мНоменклатура.Наименование ПОДОБНО "%Тщеслави%"

Этот запрос (время выполнения 2-3 секунды, еще дольше, но это и было понятно, просто пишу для анализа):
ВЫБРАТЬ
    мНоменклатура.Ссылка КАК Ссылка,
    мНоменклатура.Наименование КАК Номенклатура
ИЗ
    Справочник.Номенклатура КАК мНоменклатура
ГДЕ
    мНоменклатура.Наименование ПОДОБНО "%Тщеслави%"
И мНоменклатура.Ссылка В ИЕРАРХИИ(&Ссылка)

Вопрос почему так долго ищет по наименованию? Нет даже мысли как это можно оптимизировать.
1 Повелитель
 
07.09.16
06:57
(0) Планируем 500 000 товаров, скорость еще думаю раза в 2 упадет при таком раскладе.
2 Повелитель
 
07.09.16
06:59
Причем у нас есть сайт 50 000 товаров, скорость самого запроса MySQL по наименованию десятые или сотые секунды.
3 чувак
 
07.09.16
07:04
(2) А что если через черный запрос?
4 МешочекЗнаний
 
07.09.16
07:05
(3) Это как?
5 чувак
 
07.09.16
07:05
(4) Запрос через com-объект СКЛ
6 МешочекЗнаний
 
07.09.16
07:07
(5) Извиняюсь что вопрос в чужой теме, но можно ссылку на статью как это использовать?
7 Повелитель
 
07.09.16
07:10
(3) Пока не рассматривали.
8 Повелитель
 
07.09.16
07:12
(7) Интересный вариант конечно.
9 Повелитель
 
07.09.16
07:13
Провел эксперимент.
Попробовал поможет ли менеджер временных таблиц.
Загнал туда весь справочник номенклатуры, а потом искал по нему. Скорость одинаковая, я удивлен.

Вот весь код из обработки:

Перем МВТ;
Перем ЗапросКэш;

Процедура КнопкаВыполнитьНажатие(Кнопка)
    ЗапросКэш.Текст =
    "ВЫБРАТЬ
    |    мНоменклатура.Ссылка КАК Ссылка,
    |    мНоменклатура.Наименование КАК Наименование
    |ИЗ
    |    КэшНоменклатуры КАК мНоменклатура
    |ГДЕ
    |    мНоменклатура.Наименование ПОДОБНО ""%Тщеслави%""";
    
    РезультатЗапроса = ЗапросКэш.Выполнить();
    ТаблицаЗапроса = РезультатЗапроса.Выгрузить();
КонецПроцедуры

Процедура ОсновныеДействияФормыЗагрузитьВКэш(Кнопка)
    
    ЗапросКэш = Новый Запрос;
    ЗапросКэш.МенеджерВременныхТаблиц = МВТ;
    ЗапросКэш.Текст =
    "ВЫБРАТЬ
    |    мНоменклатура.Ссылка КАК Ссылка,
    |    мНоменклатура.Наименование КАК Наименование
    |ПОМЕСТИТЬ КэшНоменклатуры
    |ИЗ
    |    Справочник.Номенклатура КАК мНоменклатура
    |
    |ИНДЕКСИРОВАТЬ ПО
    |    Наименование";
    
    РезультатЗапроса = ЗапросКэш.Выполнить();
КонецПроцедуры

Процедура ПриЗакрытии()
    МВТ.Закрыть();
КонецПроцедуры

МВТ = Новый МенеджерВременныхТаблиц;
10 Повелитель
 
07.09.16
07:14
(9) Вот обработка сама: https://yadi.sk/d/9M2UCJ04ur848
11 Провинциальный 1сник
 
07.09.16
07:18
"подобно" никак не соптимизируешь, если в начале стоит "%"
12 Провинциальный 1сник
 
07.09.16
07:19
(11) за исключением формирования специфического индекса по лексемам, как это сделано в механизме полнотекстового поиска
13 чувак
 
07.09.16
07:24
Как то так:

Connection = Новый COMОбъект("ADODB.Connection");
Connection.Open(стрПодключения);
RS = Новый COMОбъект("ADODB.Recordset");

RS.Open("SELECT *  FROM [BaseName].[dbo].[_Reference10]
Пока RS.EOF() = 0 Цикл
    //ту что-то надо делать
    RS.MoveNext();
КонецЦикла;
RS.Close();
Connection.Close();
14 Провинциальный 1сник
 
07.09.16
07:27
(13) А смысл переносить на прямые запросы? Узкое место тут - seq scan по таблице без индекса, ибо like начинается с "%".
15 Jonny_Khomich
 
07.09.16
07:28
ищи не каждую номенклатуру по отдельности, а весь список скопом.
16 Повелитель
 
07.09.16
07:36
(15) Как понять весь список?
17 Jonny_Khomich
 
07.09.16
07:39
(16) ты каждый раз ищешь по 1 номенклатуре? Надо искать сразу много?
18 Повелитель
 
07.09.16
07:41
(17) Операторы ищут, например по названию книги, в отбор может попасть несколько книг.
19 Повелитель
 
07.09.16
07:41
Вопрос про менеджер временных таблиц.
Когда делаешь ПОМЕСТИТЬ, данные где хранятся в памяти сервера или во временной таблице?
Вроде помню что во временной таблице в SQL, но не уверен.
Если во временной таблице, то понятно, почему скорость не увеличивается.
20 Провинциальный 1сник
 
07.09.16
07:43
(19) Сервер в любом случае эффективно кэширует, и разницы нет, ибо для поиска надо пробежаться в среднем по половине всех записей. Решение проблемы - полнотекстовый индекс. Можно попробовать заюзать полнотекстовый поиск 1с. Ну или изобрести свой велосипед, чтобы не быть завязан на мутные 1совские алгоритмы..
21 Повелитель
 
07.09.16
07:44
(20) Спасибо, полнотекстовый поиск тоже рассмотрим.
22 Провинциальный 1сник
 
07.09.16
10:18
(21) Я бы делал так. Создал регистр сведений с двумя измерениями - Лексема и Ссылка. В подписке на событие "при записи" справочника Номенклатура создаю записи в этом регистре по каждому слову из наименования и ссылке на элемент справочника. Ну и первично обработкой заполнить этот регистр по существующим данным.
А дальше, при подборе по слову делаем запрос по измерению регистра, и вытаскиваем ссылку.
23 H A D G E H O G s
 
07.09.16
10:45
(22) Отличный велосипед реализации полнотекстового поиска :-)
24 Повелитель
 
07.09.16
11:14
(22) Классный вариант, спасибо ))
25 Fragster
 
гуру
07.09.16
11:16
26 Повелитель
 
07.09.16
11:17
(25) Эх 19 августа ИТС закончился, только наверно в конце сентября новый оформим.
27 Fragster
 
гуру
07.09.16
11:23
28 Fragster
 
гуру
07.09.16
11:23
а вообще вся информация по полнотекстовому поиску есть в СП
29 тарам пам пам
 
07.09.16
11:32
Собственно да, почему для полнотекстового поиска не использовать механизм полнотекстового поиска?
И еще - 1с умеет сама по части строки искать (даже без полнотекстового поиска), попробуй в свойствах справочника на закладке "Поле ввода" установить способ поиска строки "Любая часть". Может 1с при этом какой-то более оптимальный запрос сгенерирует.
30 H A D G E H O G s
 
07.09.16
11:34
(29)
"Может 1с при этом какой-то более оптимальный запрос сгенерирует."
*facepalm
31 Повелитель
 
07.09.16
11:35
(29) У нас обычные формы, способ поиска строки "Любая часть" это для управляемых по-моему.
32 ViSo76
 
07.09.16
11:37
(29) Запрос написал топикастер. 1С не будет переписывать запрос, да и что тут перепишешь в like?

Правильно подсказывают механизм полнотекстового поиска платформы использовать. На мой взгляд это самый оптимальный вариант.
33 тарам пам пам
 
07.09.16
11:42
(30) ну почему сразу facepalm, 1с должна хотя бы ограничение на количество записей поставить. Плюс есть тот же CONTAINS, который вроде бы побыстрее LIKE работает.
34 Метранпаж
 
07.09.16
11:43
(33) Кому должна?
35 Метранпаж
 
07.09.16
11:44
а насчёт contains
мНоменклатура.Наименование ПОДОБНО "%Тщес%лави%"
36 xafavute
 
07.09.16
11:47
(33) Ты наверно и планы этих запросов смотрел?
37 H A D G E H O G s
 
07.09.16
11:48
(33) чудес не бывает.
Это физика этого мира, ничего больше

http://www.sql.ru/articles/mssql/2007/012302seekpredicates.shtml
38 H A D G E H O G s
 
07.09.16
11:50
like %ЗначениеПоиска - это один в один аналог ситуации пропущенного поля поиска в составном индексе.
39 Лефмихалыч
 
07.09.16
11:56
там план проще некуда
<1C>
Index Seek(
        OBJECT:(
            [db].[dbo].Справочник.Номенклатура.[Индекс по Наименование, Ссылка] AS [T1]),
                SEEK:([T1].[Наименование] > [Expr1004] AND [T1].[Наименование] < [Expr1005]),
                    WHERE:([db].[dbo].Справочник.Номенклатура.[Наименование] as [T1].[Наименование] like [@P1]
            ) ORDERED FORWARD
        )
</1C>
в нем нечего совершенствовать и ускорять.

Если надо быстрее, придумывайте что-то с аппаратной частью. Ну, или еще лучше - глубоко-глубоко задумываться, а надо ли на самом деле часто такой лайк на сервер отправлять.
40 ptiz
 
07.09.16
11:58
Сделать маленький регистр, где будет измерение - Ссылка на товар, и ресурс - Наименование.
По меньшей таблице быстрее отработает.
41 ptiz
 
07.09.16
12:01
Еще можно добавить "ПЕРВЫЕ 10".
А остальные результаты - выдавать по требованию через отдельную кнопку "Показать еще".
42 xafavute
 
07.09.16
12:02
(41) Это поможет, если первые 10 найдутся быстро, а если в самом конце, то нет
43 Лефмихалыч
 
07.09.16
12:02
(40) если у ресурса не включить индексирование, то будет только дольше. А, если включить, то будет так же
44 ptiz
 
07.09.16
12:06
(43) Нужен эксперимент. В справочнике Номенклатура, обычно десятки реквизитов, и таблица может быть на порядок меньше.
45 Лефмихалыч
 
07.09.16
12:10
(44) Запрос из сабжа генерит index seek по индексу, в котором только два поля. У справочника по индекс (наименование+Ссылка) генерится платформой автоматом, если наименование длиннее нуля. А вот ресурсы в индекс РС попадают только после включения у них индексирования. Соответственно, если у твоего РС будет индекс (Наименование+Ссылка), то в лучшем случае он даст точно такой же план и точно такую же производительность. В худшем - это будет table scan без производительности вообще.
46 ViSo76
 
07.09.16
12:23
Можно реализовать алгоритм с разбиением слова на буквы, с ссылками и указанием позиции в слове, и простым сгенерированным запросом вытаскивать нужную ссылку путём подсчёта их количества, но таблица будет очень большая
47 ptiz
 
07.09.16
12:41
(45) Да, наверное ты прав :)
Только наверное index scan ?
48 Повелитель
 
07.09.16
12:55
(41) В рабочем запросе у нас стоит Первые 10, только цифра другая, я об этом в (0) писать не стал, так как на производительность это не влияет. Пробовали по всякому.

(40) Подобный вариант описан в (22), но я понял он работать не будет.
Так как ускорение можно добиться если использовать "=", а там тоже придется использовать ПОДОБНО.
49 xafavute
 
07.09.16
12:56
(47) Индекс скан - это вообще не использование индекса.
Просто этот индекс оказался кластерным
50 xafavute
 
07.09.16
12:57
можно пойти не прием: переименовать все номенклатуру в стиле магистра йоду. Ключевые слова в начало
51 Повелитель
 
07.09.16
12:58
(44) Подобный эксперимент я проводил,
Если брать 2 реквизита Ссылка и Наименование, то от количества колонок в таблице из которой идет выборка, время выполнения запроса не сильно зависит.

Время выполнения запроса увеличивается если выбирать не 2 поля Ссылка и Наименование, а допустим еще 10 других.
52 xafavute
 
07.09.16
12:59
(51) план запроса так и не научился смотреть?
53 Повелитель
 
07.09.16
13:00
(52) Смотрю туда очень редко, так как примерно представляю какой 1с для SQL запрос подготовила. Повторюсь примерно.
54 ptiz
 
07.09.16
13:01
Чисто фантазия: все наименования склеить в большую  хранящуюся в памяти строку, разделенную на блоки спецсимволом, и на неё натравить: или просто поиск подстроки, а если недостаточно - регулярные выражения. Но чтобы они возвращали номер блока.
Но при изменении наименования надо строку перестраивать.
55 Лефмихалыч
 
07.09.16
13:05
(47) если  ресурс не индексировать, то будет table scan, т.к. не будет индекса, по которому можно было бы искать
56 Повелитель
 
07.09.16
13:05
(54) В памяти в каком месте?
У нас еще есть сайт на 1С Битрикс, там технологии позволяют хранить кэш в памяти. В 1с даже не слышал о таких возможностях.
Временные таблице, хранятся на диске.
57 Провинциальный 1сник
 
07.09.16
13:05
(48) "Так как ускорение можно добиться если использовать "=", а там тоже придется использовать ПОДОБНО"
ПОДОБНО тоже использует индекс, если искать с начала слова.
58 Провинциальный 1сник
 
07.09.16
13:06
(57) То есть с начала поля, не ставить в начале выражения %
59 Повелитель
 
07.09.16
13:07
(58) Понял, спасибо, проверил, быстро работает.
Тогда да (22) это вариант хороший.
60 Лефмихалыч
 
07.09.16
13:08
любые оптимизаяйца должны начинаться с вопроса: "назачем это, что нуждается в оптимизации, вообще нужно?" Т.к. идеальная оптимизация объекта будет тогда, когда объекта вообще исчезнет , а функция его будет выполняться
61 Torquader
 
07.09.16
13:12
Обычно ищут части слов - соответственно - наименование разбит на слова и уже искать по таблице слов, потом полученную выборку из таблицы слов (там ссылки на номенклатуру) выбрать из таблицы номенклатуры.
Проблемы будут начинаться, если кто-то сокращает слова - но это уже никакой поиск не найдёт.
Также можно повыкидывать из поиска все знаки препинания - и проверять на них уже полученную предварительным поиском номенклатуру.
Если пользователь указывает несколько слов, разделённых пробелом - то сначала можно искать каждое слово, а потом по результату выбрать те, где первое идёт перед вторым (если, конечно, пользователю это важно).