Имя: Пароль:
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
Обычно ищут части слов - соответственно - наименование разбит на слова и уже искать по таблице слов, потом полученную выборку из таблицы слов (там ссылки на номенклатуру) выбрать из таблицы номенклатуры.
Проблемы будут начинаться, если кто-то сокращает слова - но это уже никакой поиск не найдёт.
Также можно повыкидывать из поиска все знаки препинания - и проверять на них уже полученную предварительным поиском номенклатуру.
Если пользователь указывает несколько слов, разделённых пробелом - то сначала можно искать каждое слово, а потом по результату выбрать те, где первое идёт перед вторым (если, конечно, пользователю это важно).
Здесь можно обсудить любую тему при этом оставаясь на форуме для 1Сников, который нужен для работы. Ymryn