<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55
global $wpdb2;
global $failure;
global $file_hist;
///// echo '<H2><b>Старт загрузки</b></H2><br>';
$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
///// echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}
$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
///// echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}
/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
///// echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
///// echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist); ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7]; ////получаем размер файла
$m_mtime_file=$masiv_data_file[9]; ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file
///// echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
///// echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
///// echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);
if ($results)
{ foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));
////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
///// echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
///// echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}
////загружаем данные
$table='vin_history'; // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация // (путь от корня web-сервера)
$delim=';'; // Разделитель полей в CSV файле
$enclosed='"'; // Кавычки для содержимого полей
$escaped='\
А сколько элементов было в справочнике?
Избавиться от «ИЛИ» в секции «ГДЕ» не пробовали?
Или это внутренние соединения таблицы сама с собой несколько раз?
Поддерживаю, приведите варианты оптимизации, которые получились «по всем правилам» и которые не сработали.
Вообще 1С рекомендует уходить от «ИЛИ» в секции «ГДЕ» и заменить на конструкцию вида «ОБЪЕДИНИТЬ ВСЕ».
В вашем случае можно было бы попробовать:
Показать
Пруф:Использование логического ИЛИ в условиях
Не понятно правда на сколько это будет быстрее в вашем случае, но официальная рекомендация такая.
(5) По идее, оптимизация через «ОБЪЕДИНИТЬ ВСЕ» — это первое, что приходит в голову. Но автор пишет: «Любые попытки оптимизации этого запроса по стандартным методикам не привели к нужному результату». Вот и гадай, что он имел в виду под «стандартными методиками».
(5) я бы добавил: нужно писать максимально простой запрос, отдельный для каждого варианта поиска.
(2) пробовали) это первое что сделали — не помогло, стоимость плана маленькая — запрос выполняется долго)
(5) да, этот вариант был первым, который использовали) не помогло
(1) несколько сотен тысяч
(6) согласен, следовало уточнить) через ОБЪЕДИНИТЬ ВСЕ переписали сразу когда увидели запрос. Результата это не дало)
(4) сходу все не вспомню, из того что делали:
— переписывали через ОБЪЕДИНИТЬ ВСЕ
— в параметр наименование передавали строку с фиксированным началом (например, вместо «%строкапоиска%» использовали «строкапоиска%».
(5) вы написали тоже самое, что делал план долгого запроса на скриншоте, за исключением того, что вы забыли сгруппировать результат. То есть 4 раза будут перебираться все элементы одной и той же таблицы. Вы как бы таким образом пишите, что вам надо его перебирать именно 4 раза.
Понятно что LIKE в индексе будет заниматься тем же самым перебором, что и без индекса. У него (у LIKE) другого варианта и нет.
Быстрее конечно перебрать все элементы 1 раз, сравнивая их на 4 различных условия.
А может кто-то все же добавил индекс на один из реквизитов при повышении совместимости? Например, до измениний были индексы только на реквизитах «Код», «Артикул», «КодРозницы». А после добавили индекс на «Наименование».
(12) проверяли, по всем полям поиска («Код», «Артикул», «КодРозницы», «Наименование») индексы были
(13)
Вот с этого и нужно было начинать. При Like и подстановочных символах не может использоваться именно поиск по индексу. Был полный перебор индексов, причем 4 разных. Во втором был просто перебор таблицы один раз.
Для таких случаев придумали Полнотекстовый поиск.
На одной из конференций Инфостарт Event, по-моему, выступал представитель компании Софтпоинт и он предложил решение задачи поиска номенклатуры, которое будет отрабатывать очень быстро.
Добавил регистр сведений с измерениями:
— Подстрока (индекс)
— Номенклатура
и регламентное задание, которое бы перезаполняло этот регистр:
А именно: разбивало бы исходную строку на подстроки:
Пример:
Туфли женские (наименование)
3-х буквенные:
туф
уфл
фли
жен
енс
нск
кие
4-х буквенные:
туфл
уфли
женс
енск
нски
ские
5-ти буквенные
и т.д.
Каждой такой подстроке соответствует номенклатура «Туфли женские». А дальше разбиваем исходную строку поиска на слова и делаем запрос к регистру, который работает без ПОДОБНО, через равно.
Да получается много данных сохраняем и огромный регистр, который строится долго, но поиск работает очень быстро.
Вот такой вариант по поиску был предложен.
В принципе, можно добавить еще измерение размер блока и сначала фильтровать по нему, чтобы избегать фильтров по строке и максимально сократить размер выборки, так же нужны оптимизации при изменении данных номенклатуры, чтобы данные регистра перестраивались без пересчета всей номенклатуры, а только измененной (допустим использовать план обмена) для регистрации измененной номенклатуры и регламентное, которое изменения этого плана обмена перебирает и строит только для указанной номенклатуры).
Все это имеет смысл только для баз где ОЧЕНЬ много номенклатуры. И люди пользуются такими извращениями потому, что деваться в общем-то некуда…
(16)
Хехе… Знаем проходили… Поищите ошибки при полнотекстовом поиске в интернете.
Да, этот механизм предназначен именно для этого, но оно же не работает как надо.
Для реально больших баз, были ошибка с дампами (отключаешь полнотекстовый поиск — все ок, выполняешь поиск дамп и вылет из программы) и место заканчивалось в папке с файлами индекса, а его же на другой диск не перенесешь в отличие от файлов того же сиквела…
Поэтому полнотекстовый поиск как бы есть, но для больших данных нужны свои велосипеды.
(5) Проверяли мы на своей базе рекомендации 1С. Из справочника «Номенклатура» нужно было отобрать данные по 8-ми условиям артикула. Отбор составлял 270 000 позиций номенклатуры с 43 реквизитами. Так вот, обычным отбором с помощью «ИЛИ» замер показал 23 секунды, а запросами с помощью «ОБЪЕДИНИТЬ ВСЕ» 25 секунд, плюс текст запроса становится совершенно громоздким. Так что не всё так просто с этими рекомендациями.
(18) На то это и рекомендации 🙂 Применять их или нет зависит от ситуации.
(15)
И когда ОЧЕНЬ МНОГО свободного места на дисках.
В тему анти-оптимизации: никогда не забуду одного случая из своего опыта. Доставшийся мне запрос собирал данные по таб. части документа. Как весь из себя правильный прог, я возмутился и переписал на «канонический» способ — получения из регистра накопления. В результате время выполнения увеличилось в разы. Пришлось вернуть обратно.
В защиту рекомендаций 1С по оптимизации запросов могу сказать, что там есть упоминание того, что запросы могут работать быстрее до оптимизации чем после, но проводить оптимизацию все равно рекомендуется по той причине, что один и тот же запрос может быстро выполняться на одном сервере и недопустимо долго на другом. А оптимизированный запрос может работать медленнее, но время его выполнения будет стабильным/предсказуемым в большинстве случаев.
Насчет скриншота итогового плана запроса есть сомнения. До этого было сканирование 4 разных не кластерных индекса, а в итоге идет сканирование по кластерному индексу, который еще и Primary Key похоже… Что-то тут не так. Он обрезанный?
(21) имхо, это рекомендации времен дбф.
(17)
Дамп — ситуация расследуемая и устранимая.
Индекс ППД, а точнее каталог кластера, легко и непринужденно переносится куда угодно симлинком или в командной строке запуска службы.
(15) Т.е. накостылили свой ППД несмотря на существование такового как в платформе, так и в СУБД.
Очень поверхностная статья без знания СУБД. Мы стукнули по телевизору и он стал показывать лучше… (С сожалению именно такие ощущения)
Нет, конечно это не оптимизация. Даже для частного случая. Это ещё выстрелит вам в ногу. Вы заставили свалиться запрос в один скан и параллелизм, почему сам поиск работает долго по каждому индексу — не разобрались. При такой оптимизации можно уже и индексы отключать. О записи то вы почему-то не стали беспокоиться.
Так можно поступить только «пока не разберемся’.
Давайте детали:
Версия СУБД. Совместимость базы. Maxdop=0? Или сколько? Почему при наличии maxdop разница в 4 раза? Очень странно. Нужны цифры…
Сколько записей в таблице, сколько записей в выборке по каждому индексу.
Прогрет ли кэш? Покажите чтения и время для каждого случая по всем (пяти) индексам отдельно.
План запроса свежий или из кэша? закэширован для какого параметра?
ПС: 5 сек — это тоже не результат. Что делает этот запрос? Если это список, то где ПЕРВЫЕ?
(15) Cвой вариант Elasticsearch?
(2) MSSLQ сам неявно избавился от «ИЛИ». Посмотрите на план запроса 8.2. Оптимизатор параллельно читает таблицу 4 раза, а затем объединяет результат операцией Concatenation. То же самое происходит при использовании UNION ALL. Пруфhttps://sqlperformance.com/2017/05/sql-plan/union-all-optimization .
(5) см. (29)
(6) Первое, что должно прийти в голову — посмотреть план запроса. В данном случае UNION ALL ничего не даст, см. (29).
Из личного опыта — никаких гарантий нет, что по одному и тому же запросу будет построен один и тот же план выполнения. То что разово сработало ни о чем не говорит, и даже не разово сработало. Может месяцами работать, а потом хоп и сюрприз.
Ну его нафиг такую оптимизацию.
(21) на уровне субд все это таблицы. Плюс регистров в том, что там могут быть собраны данные из нескольких типов документов. Ну и различные итоги и агрегаты. Если точно знать, что запросом будем получать каждую запись и по одному типу документов, то можно и таблицу документа взять.
Используйте для поиска более подходящие инструменты, например, Elasticsearch.
(10) перепишите статью и заново на модерацию. А то вам теперь только про это и будут говорить.
(29) Конечно избавился и потратил на это (на оптимизацию) своё время.
Как-то не однозначно все. Если даже взять первоначальные данные — 5 секунд на поиск подобных в справочнике из несколько сотен тысяч элементов. Не многовато? Для примера аналогичный запрос по справочнику с 900 тысяч элементов отрабатывает менее секунды (если быть точнее, около 300-400 миллисекунд). Самое интересное, что конструкция ВЫРАЗИТЬ никак не влияет на производительность — +/- время одинаковое.
(17)
Очень даже можно перенести. Windows уже давно умеет хард/софт линки.
(25) Повторю — это не моя реализация. Это было на одном из докладов IE, сотрудник Софтпоинта рассказывал о таком способе.
С другой стороны, если это будет работать быстро, то почему нет?
А почему во втором плане запроса есть сортировка?
(5)
В данном случае если вместо ПОДОБНО было строгое равенство, тогда было бы оптимальнее: было бы 4 поиска по индексам и объединение.
(26)
Версия СУБД: Microsoft SQL Server 2008 R2 10.50.6000.34
maxdop = 8
compatibility level = 100
Проверялась работа с разными значениями maxdop, в том числе и с выключенным (=1), результат значительно не изменялся.
План запроса свежий или из кэша? закэширован для какого параметра?
Кэш прогревался. Тестирование выполнялось с предварительной очисткой кэша и его прогревом.
запрос выполняет поиск номенклатуры по части строки, поиск выполняется по разным реквизитам (это не динамический список)
Покажите чтения и время для каждого случая по всем (пяти) индексам отдельно.
Эту информацию, к сожалению, сейчас нет возможности предоставить — доступа к базе уже нет.
(34)
Напишите, пожалуйста, где можно прочитать про этот инструмент и как с ним работать в связке с 1С
(41) Да, согласен, поиск на равенство работал бы максимально быстро. Но поиск на строгое равенство не всегда устраивает клиента.
Отличная статья как не надо оптимизировать запросы я считаю
Решение задачи методом подселения козла.
Подозреваю юзеры жаловались и на 5 сек поиск номенклатуры, им сделали 20 сек, а потом вернули 5 сек и наступило счастье )
На самом деле не хватает информации по задаче.
Самое главное — сколько секунд ищется такой конструкцией
Показать
и по какому полю чаще всего пользователи ищут
и если они в большинстве случаев правильно вводят начало слова а я думаю 100% они не ищут по середине — то можно искать по равенству, а не по подобию — это будет 0.5 сек к примеру вместо 5 сек
(10)Т.Е. это уже не актуально писать через объединить ?
(45) там вероятнее всего проблема в железе, потому что даже подобие отрабатывает на сотнях тысяч элементов менее секунды на нормальном сервере.
(42) Спасибо за детали.
Очень жаль, что уже нет доступа к данным и больших подробностей. Можно было хотя бы отдельно таблицу выдрать/сохранить.
Я такие вещи тестирую прямо в SSMS. Можно рекомпиляцию делать (для избежания снифинга), хоть как-то контролировать кэши, можно чтения видеть, замеры и т.п. Из 1С проводить тесты — так себе…
Очень важный момент: как бы повел себя оптимизатор на 2012-2017 версиях. Теперь мы этого не узнаем. ((
Время скана кластерного то точно должно было меняться. Интересно сколько оно занимало при =1.
Во всех подобных случаях не стоит рассматривать примеры запросов как что-то универсальное (а-ля вот такая таблица с таким-то количеством строк). Подобные странности проявляются на определенных данных, с определенным статистическим распределением значений.
PS: прошу прощения за лишнюю резкость в предыдущем посте.
(38)https://habr.com/ru/post/50878/
(15)На мой взгляд безсмысленная оптимизация, СУБД самостоятельно это делает. И вообще Полнотекстовый поиск для чего вам?
Я бы попробовал вручную создать индекс состоящий из ссылки и всех полей поиска. Скорее всего запрос стал бы работать быстрее 5 секунд.
(15)
Бред, а не решение. Автор этого решения, видимо, даже не подумал о том, что 99% этих буквосочетаний не будут нужны никогда. Потому что в 99.99% случаев пользователи ищут по началу слова, а не по середине, если нужны «туфли», то никто не будет писать «уфл».
Затем автор этого бредового решения не подумал о том, что даже если номенклатуры в справочнике миллион, то даже группировка по двум первым буквам уже даёт выборку всего в пару тысяч элементов, что вполне уже подъёмно даже для 1С.
Соответственно, если уж хочется решать это всё через регистр, то можно весь миллион номенклатуры разбить по словам, у каждого слова взять две-три первые буквы, а дальше уже составлять индекс — «туф» как начало любого из слов в номенклатуре присутствует в этих двух тысячах номенклатур. А во время поиска, когда пользователь набрал «туфли ж», выбирается вся номенклатура, у которой индекс = «туф» (равно, не подобно), дальше уже из этих пары тысяч строк по Имя Подобно «%туфли ж%» за несколько мс выбирается всё нужное.
Нет террабайтов бесполезных индексов, нет часов ожидания перестроения бесполезных индексов, нет ожидания пользователей.
(46)Это не обязательно в железе, может быть фрагментация индексов или БД, судя по переходу с 8.1 там все не новенькое
(45) Вот как раз по середине и ищут, например такая фраза «цем иск 50», означает «Цемент (ОАО «Искитимцемент») 50кг /25″.
У нас примерно так же сделан поиск и простых альтернатив этому я не вижу.
У нас было искать в найденном.
(43) Вот ссылка на материалы мастер-классаhttps://github.com/FoxyLinkIO/FoxyLink/tree/develop/samples/is-this-design-2019
(54)Т.е. вы считаете что поиском ПОДОБНО &Наименование
«цем иск 50», найдется «Цемент (ОАО «Искитимцемент») 50кг /25″
???
(52)
Я передал саму мысль. Понятное дело, что в чистом виде без оптимизаций никак.
(57) Если разбить по словам и сделать несколько запросов то найдется.
Почему не попробовали сделать «составной» реквизит — поле поиска? Например: КлючАналитикиПоиска (строка, 200, индекс) = Наименование + Код + ПолнАртикул + ….;
Во-первых, такая строка 99% будет уникальной, а значит и индекс будет селективным.
Во-вторых, это будет один индекс, а не 3 (5,10 и т.д.), в плане будет поиск по 1-му индексу, а не по 3-м и последующая конкатенация результатов.
Очевидное решение, лежит на поверхности, неужели никто не догадался???
(5)Результат Вашего запроса не будет равен изначальному… )
(61) плюс можно сделать такой реквизит чуть более «интеллектуальным», проверять при сложении ключевых полей их строковое «покрытие» друг другом и не дублировать строки при сложении, например:
Наименование = Стол дубовый
Код = 00012345;
Артикул = 12345;
ПолноеНаименование = Стол дубовый лаковый производство Россия
КлючАналитикиПоиска = 00012345 Стол дубовый лаковый производство Россия
Еще можно административно принять в компании шаблон заполнения всех этих полей, написать обработчики на эти поля, шаблон поиска для подстановки в запрос формировать также, как сам ключ. Уже масса вариантов. А пока на «оптимизацию» ну никак не тянет, уж извините
(64) и чем этот индекс поможет в поиске, скажем «стол»? Потребуется искать по Like %стол%. Будет так же полное сканирование всего индекса. А из-за селективности = 1, будет такое же количество записей, как и в самой таблице. Да, тут будет только 1 индекс, но не сильно будет отличаться от просто полного сканирования таблицы.
Да еще и длины строки может не хватить поместить все выбранные реквизиты.
(66) именно так, полное сканирование индекса в этом случае. Только там проверка по всем 3 полям, а тут по 1-му. Должно быть быстрее в любом случае. Плюс все-таки сортировка же есть в индексе, а в самой таблице (кластерном индексе) — там сортировка по ссылке. Так что быстрее все-таки будет
(68) сортировка в данном случае (при полном сканировании) не играет никакой роли. Да, Сравнений будет меньше, но принципиальной разницы не получится.
(69) Вы забываете еще и про статистику, коллега. И касаемо фулл-скана таблицы справочника навряд ли она будет использована, потому что поиск идет не по ссылке. А вот в случае с отдельным реквизитом — да. Согласно документации, статистика создается автоматически при создании индекса и дальше уже заполняется. Так что после ваших нескольких поисков like %стол% — она заполнится и запрос отработает быстрее. Система будет знать, что часто ищут по %стол% и будет знать, какие строки соответствуют этому условию.
Это конечно требует проверки на практике, но повторюсь — решение то очевидное.
(70)
И как поможет тут статистика? Статистика это не еще одна разновидность индекса.
(71) думаю, что поможет
Начиная с версии MS SQL 2005:
«String summary statistics: частота распределения подстрок при анализе символьных полей. Помогает оптимизатору лучше оценивать селективность условий с оператором LIKE.»
«Объект статистики содержит сводную строковую статистику, позволяющую уточнить оценку количества элементов для предикатов запроса, использующих оператор LIKE, например WHERE ProductName LIKE ‘%Bike’. Сводная строковая статистика хранится отдельно от гистограммы и создается в первом ключевом столбце объекта статистики, если он имеет тип char, varchar, nchar, nvarchar, varchar(max), nvarchar(max), text или ntext.»
Ссылки на пруфы могу прикрепить, но думаю и сами найдете легко и просто
(72)
Вот это ни о чем не говорит? Эта статистика нужна оптимизатору плана запросов для выбора таблиц/индекса в котором делать поиск. Т.к. поиск по определению тут невозможен, то будет выбор: или перебор таблицы или индекса. Никакого дополнительного увеличения быстродействия статистика не даст.
(45) Спасибо за критику)
запрос с ПОДОБНО только по одному полю выполнялся после повышения совместимости около 5 секунд
запрос на равенство — меньше 0,5 секунды.
и если они в большинстве случаев правильно вводят начало слова а я думаю 100% они не ищут по середине — то можно искать по равенству, а не по подобию — это будет 0.5 сек к примеру вместо 5 сек
то что на равенство будет работать в десятки раз быстрее — сомнений нет)
По поводу «100% не ищут по середине» — тоже так думали, но вариант с поиском по строке с фиксированным началом не устроил пользователей — искали и по середине тоже, хотя работал он быстрее.
(73) Логика построения плана согласно статистике — это все хорошо и понятно.
Вы меня раззадорили. Я не поленился и провел эксперимент.
У меня есть в тестовой базе документ ЭлектронныйЗаказ. Всего 2 млн строк в таблице документа.
Вот такой запрос:
В поле «Комментарий» пишут адрес доставки, так что цифра «1» там встречается очень и очень часто.
1. Вариант 1. Поле Комментарий не индексируется.
Запрос после прогревания кэша стаблильно отрабатывает за 20 с небольшим секунд. Возвращает 178 тыс. строк.
План запроса точь в точь как у автора (за небольшим исключением, у меня в базе есть еще разделение данных по общему реквизиту «Организация», так что у меня не scan, а seek индекса (но в данном контексте это не существенно).
seek кластерного индекса (то есть, по сути — самой таблицы) 99% — параллелизм 1%
Оптимизатор запроса подсказывает, цитирую:
Показать
2. Вариант 2. Я включил для поля «Комментарий» — «Индексировать с доп. упорядочиванием».
Тот же самый запрос. Прогрел кэш. Вернулись те же 178 тыс. строк. Отработало за 1.9 секунды.
План запроса:
Поиск в индексе (не-кластерный) 100% — Вложенные циклы (внутреннее соединение) 0%
Compute scalar 0% ——————————
Оптимизатор никаких индексов до-создать не советует.
20+ секунд —> 1.9 секунды.
Так что данная логика вполне жизнеспособна.
Не верите — возьмите и повторите, как говорится….
Надеюсь, звучит убедительно.
Планы прикладываю.
(48) Спасибо Вам за развернутый комментарий. Возьму на заметку некоторые моменты)
Все нормально, к критике отношусь положительно — в ней рождается истина)
(77) можно ли сделать к тому же комментарию четыре разных поиска с условием или?
Будут ли они параллельно выполнять чтение?
(80)
Да можно конечно, только результат будет такой же как у автора — план разобьет эти ИЛИ на несколько seek-ов и потом будет объединять…
Будет ли параллельно выполнять — это уж как у вас в БД настроен параллелизм.
Я поэтому и предложил — «составной» строковый реквизит, грамотно заполненный, с отдельным индексом. Думаю, из исходных 5 секунд можно сделать 0.5
(77) я правильно понял, что эксперимент проводили со строковым реквизитом неограниченной длины? И еще ему и индекс сделали?
А теперь то же самое с нормальным реквизитом. И не %1%, а более осмысленное типа %стул%. Чтобы приблизить к оригиналу.
И по поводу кеша. Вот один пользовать делает %стол%, второй %белый стол% и т.д. Какая вероятность попадания в кеш при таком поиске?
(86) Реквизит имеет ограниченную длину. 150 символов.
Так что он нормальный. %1% вполне осмысленное в моем случае, так как в этом поле хранится что-то вроде:
«12345 На деревню дедушке»
«Москва, улица Мира, д. 134, 345671»
«Позвонить после обработки по телефону +79991234567»
и т.д.
Так что мой эксперимент очень близок к оригиналу. Шаблон %1% как видите — не особо избирательный. И тем не менее, на порядок ускорилось.
(86) я понимаю Ваш скепсис. В теории сказано, что like не может использовать индексы. И тем не менее — результаты налицо. Я доподлинно не знаю, как это работает. Имеется ввиду — «внутри» операций scan и seek. Может в seek там хэши строк вычисляются и сравниваются, может еще что.
Для алгоритма какая разница, какой шаблон %стол% или %белый стол%? Я думаю, никакой абсолютно.
Ради интереса, сделал вот такие шаблоны:
«%аптека%» 98 тыс строк вернулось
«%ООО%» 59 тыс срок
«%стол%» 69 строк
«%стул%» 0 строк (ну не торгуем мы стульями, уж извините xD)
«%аптека фарм%» 3 строки
Везде результаты 1.9-2.1 секунды.
Я на этом эксперимент закончу, можете повторить при желании и отписаться о результатах
(15) Это очень избыточное решение. (52) — движение в верном направлении, Но еще правильнее выделить из заполненной части строк все возможные «суффиксы». Например, «абракадабра» разобьется на «абракадабра», «бракадабра», «ракадабра», «акадабра», «кадабра», «адабра», «дабра», «абра», «бра», «ра», «а». На слова делить не нужно!
Тогда обычный индекс легко и быстро поможет находить слова любой нужной длины.
В общем то, полнотекстовый поиск именно так и устроен. Можно еще про суффиксные массивы и деревья почитать. ВКопипастомер , кстати, применяется. Избыточность небольшая — для каждой записи справочника создается в среднем L записей, где — L — средняя длина заполненной части строки. Например, для миллиона записей будет 10 миллионов записей суффикса. В случае (15) таких записей будет гораздо больше — L x L / 2.
По моему, 5 секунд слишком много, нужно либо полнотекстовый поиск настроить, а если не получится, сделать свой, самодельный. То есть, нужно сосредоточить борьбу не на отрезке 5 — 20 секунд, а 0.1 — 5.
(93) подскажите пожалуйста, где можно подробнее почитать про полнотекстовый поиск и можно ли в 1с как то его регулировать (соотношение обьем-скорость, обновление), кроме того что отключить и поиск и фоновое задание по его обновлению.
(93)
Не понял, чем эти суффиксы помогут для поиска. В вашем примере «абра» попала в суффиксы, потому что она два раза в слове встречается. Возьмём «туфли женские». Начинаю писать «туф», ни один из суффиксов («уфли женские», «фли женские» и т.п.) мне не поможет в поиске. И опять приходим к десяткам миллионов ненужных данных. При этом если у нас была таблица, где есть:
, то поиск занимал бы миллисекунды. Я реализовывал такой поиск городов. Задача была — реализовать внешнюю обработку на базе на замке, соответственно, реестр хранился в виде текста, извлекался оттуда в соответствие, где ключ — две первые буквы названия, значение — массив всех данных о городах, которые начинаются на эти две буквы. В файле было 250 тысяч строк, первичное кэширование (из файла JSON в соответствие) занимало 4 сек, поиск занимал миллисекунды, пользователь вводил от двух букв и больше и ему показывалась выпадающая подсказка, пользователь вообще не ощущал, что что-то в фоне происходит. А в фоне отбирались первые две буквы, получался соответствующий массив из пары сотен-пары тысяч строк и по нему искалось Подобно «ТоЧтоВвёлПользователь%». А уж если использовать не внешние объекты, которые надо конвертировать, а БД, то там и без кэширования можно обойтись.
В результате размер индекса или равен размеру справочника, или в 2-3 раза больше (если индексировать начало каждого слова в наименовании). Искать можно только по началу слов, но, повторюсь, в моей практике я ни разу не встречал, чтобы кому-то пришло в голову искать «туфли» как «уфли». Более того, надо, наверное, всерьёз поработать над бизнес-процессами и НСИ, если такая нужда у кого-то возникает. Даже, как тут где-то указывалось, если у меня «Искитимцемент цемент мешок 10 кг», то не знаю, зачем бы я искал «мент» или «шок».
Поэтому, повторюсь, так и не понял, зачем нужно резать слова на суффиксы.
Про ПП в 1С пишут, что были глюки и ошибки. Сам я когда-то включал ППИ в базе 1С, но ни разу не дождался, чтобы он построился до конца. Было это довольно давно, но осадочек остался.
(95) не всегда можно уложиться в префикс.
Пример:
— пеностирол
— пенополистирол
— полистирол
Как найти их все?
(96)
Давайте определимся — мы говорим о пользователе, который ищет конкретную номенклатуру или об абстрактной ситуации, в которой кому-то, например, для отчёта, понадобилась номенклатура со всякими вхождениями?
В дин.списках 1С есть поле поиска, которое также может помочь в поиске вхождений. Как и форма поиска. Для описанной вами ситуации вполне подойдёт. Если же мы говорим о ситуации из статьи, когда, например, оператору, нужно подобрать определённую позицию номенклатуры в документ, «пенос» даст первый, «пеноп» даст второй, «поли» третий из ваших элементов. Плюс на «пено» выпадут оба первых, можно будет выбрать вручную.
(97) почему принудительно ограничиваете сценарии поиска номенклатуры? К данному примеру, нужно найти утеплитель разновидности стирол. Какой конкретно (поли- пено- пенополи-) может выбирать заказчик. Тут главное найти их все из доступных и ему показать.
Если ограничивать только узкими рамками для конкретного сценария, то можно сказать, что нечеткий поиск вообще не нужен. «Мы вот сразу знаем наименование всех номенклатур».
(98)
Сценарии могут быть разные, для разных сценариев могут быть разные подходы.
Для вашего сценария вообще ничего изобретать не нужно. Подходит интересующийся клиент — «А что у вас из стирола есть?» Менеджер вбивает в типовой поиск «стирол» и получает все вхождения. Время ожидания зависит от базы, пусть даже 20 секунд — это не критично для этого сценария, никто не умрёт. За минуту собрал несколько позиций, показал цену, рассказал о товаре.
Другой сценарий — сидит оператор, например, на складе, и целый день вбивает в документы номенклатуру. Ему нужны «пенос», «поли», «пеноп». Позицию он хотя бы примерно знает. А может и совсем знает, если вбивает по бумажке, например, или по памяти из частых позиций. Время поиска для него критично, 20 секунд на каждую номенклатуру — это не только невыгодно, но и психически сложно, будет бунт.
Изобретать механизмы для первого сценария — ну, наверное, можно, если прям большущая нужда. Но мешать его со вторым, делать общий механизм — это раздутые трудозатраты на разработку и негарантируемый результат (по вашему сценарию придётся делать десятки, если не сотни миллионов индексов, очень не уверен, что вообще будет существовать приемлемое по затратам решение, которое даст меньше секунды на поиск). Для второго сценария описанный мною механизм как один из вариантов по трудозатратам выйдет в несколько часов. И эти смешные затраты решат проблему по одному из сценариев здесь и сейчас.
Поэтому никакого «ограничения» сценариев нет, есть разумное разделение сценариев по нуждам, реализации и затратам. Если есть какая-то панацея — предлагайте. Конечно, одно решение на все случаи жизни лучше, чем несколько. Если нет, тогда два разных эффективных решения или хотя бы одно эффективное на один сценарий — это лучше, чем полный бардак в ожидании панацеи.
(99)
это называется подогнать вопрос под ответ.
Вариантов «приставок» может быть неограниченное количество. Помнить все довольно трудно. Причем это только для одного корня. А этих ситуаций может быть неограниченное количество. Вот корень слова запомнить проще, чем все возможные «приставки»
Мы же рассматриваем универсальное решение. Вообще такое решение давно придумано: ППД, но в данном случае его отбросили и изобретают свой велосипед.
(100) я бы её назвала это полнотекстовым поиском.
Предположи, товар в базе может называться английскими буквами или начинаться с кавычки, слова, которое обычно не произносимо или сокращения.
Можно конечно настроить rls, но что если оператор один, а привязки rls к клиенту нет?
К складу эту роль ограничения rls играют остатки, и то, если они есть.
Нет, это называется придумать какую-то задачу, которая не решается данным решением, и с радостью заявить, что решение не решает вообще ничего.
Я вам описал сценарий, с которым я работал и который успешно решил, этот сценарий сильно похож на тот, который описан в статье. Есть замеры и трудозатраты.
По вашему сценарию, очевидно, нужно другое решение. Вы при этом никакого другого решения не предлагаете, при этом заявляете, что решение совершенно другого сценария плохое, потому что оно не решает ваш сценарий. Ну ок, пойду удалю код у клиента, скажу, что был неправ, на форуме сказали, что решение неправильное.
(102) скорее это попытка определить, какую задачу решает некое почти универсальное решение.
(103)
Задача описана чуть выше, в первом моём комменте. И потом ещё пару раз повторил описание)
(102) все началось с вашего вопроса: «Не понял, чем эти суффиксы помогут для поиска. В вашем примере «абра» попала в суффиксы, потому что она два раза в слове встречается. Возьмём «туфли женские». Начинаю писать «туф», ни один из суффиксов («уфли женские», «фли женские» и т.п.) мне не поможет в поиске»
Т.е. вы сами придумали себе свой сценарий и под него все подводите. Обсуждение же было про универсальный поиск.
Никто не говорил, что ваше решение не имеет права на жизнь. Вы просто влезли в обсуждение универсального решения со своим узкоспециализированным и выдаете его как единственно верное.
учитывая, что было обсуждение предложенного выше варианта решения, то это можно принять за просто попытку оскорбления.
Удачи вам. Дальше продолжать общения с вами не вижу смысла.
(105)
Повторюсь, сценарий в статье описывал похожий на мой сценарий. Поэтому я привёл решение своего сценария.
По суффиксам я не понял тогда и не понимаю сейчас, чем они могут помочь. У нас есть справочник с миллионом строк, по которому поиск осуществляется очень долго. Нам предлагается создать ещё один справочник, больше первого в 10-50 раз, запустить работы по его наполнению и поддержке — резать слова, собирать их по буквенно по 2-3-4-5 и так до скольки?, пересобирать куски при каждом изменении каждой номенклатуры и при создании новой, перестраивать индексы базы по этому монстру каждый раз, а с блокировками что? Это в фоне будет выполняеться? Т.е. новая номенклатура найдётся только завтра, после перелопачивания? Или сегодня подождём полчасика, пока всё перестроится? Ночных операторов нанимать, чтобы днём не дай бог никто номенклатуру не поменял)) А колво букв какое — 10? А если пользователь наберёт 11 букв, то мы ему вывалим критикал эррор и выключим 1С, чтобы не повадно было) Или все буквы сколько есть? Представляю, что за индекс будет там, где номенклатура «Шарикоподшипники самзанные КЛМКПСФНС103443КУППРЕТЫФ Искитимглавшарикоподшипник»))
Т.е. было предложено решение, которое вроде бы как что-то должно решать, но я пока вижу проблемы и не вижу замеров этого «универсального» решения. Поэтому я и предложил сделать из абстрактного «а давайте искать абракадабру по бре!», который лично я не встречал никогда, более жизненный вариант сценария, с которым работал неоднократно — искать по началу слов.
Постараюсь не сильно реветь от этой потери)) Потому что так хочется на техническом форуме читать обидки, а не технические решения, а тут на тебе, обломали меня))
(95) С алгоритмами на строках часто так — они не очевидны. Вот, например, вы хотите найти все вхождения подстроки в строку. Предполагаю, вы думаете, что нужно по очереди прикладывать подстроку к строке и производить сравнение, то есть тратить N х М операций, где М — длина строки, а N — подстроки. Алгоритм Боурера-Мура (изобретенный, кстати в 1984 году, когда кругом повсюду уже были компьютеры) работает по другому и быстрее. Но это я отвлекся…
Относительно «туфель». Суффикс здесь не лингвистическое понятие. Я же привел пример: «абракадабра» — слово и «абракадара» — его первый «суффикс». То есть «туфли женские» — слово и «туфли женские» — один из его суффиксов.
Если вы хотите сэкономить и не хранить «уфли женские» как малоиспользуемое сочетание, то «уф» В ЭТОМ МЕСТЕ тоже зря будет храниться.
А тут вы сможете найти очень быстро и точно за одно обращение к индексу целые «ботинки женские», а боты, ботильоны и другая ботва будет пропущена.
Вообще минимизировать число разделяющих признаков можно, если задано множество наименований. Но тут мы не говорим про словарь и его возможные ограничения, тут ведь и артикулы и коды есть, то есть строками считаем произвольный набор символов, где и «уфли» могут какой-то смысл иметь. Не расслышал первую букву, например, в названии улицы или фамилии. Акунин или Окунин — как тут найти? — Пиши «кунин», полнотекстовый поиск его сразу найдет.
То есть предложенная схема хранит одновременно и единички и двойки и тройки и четверки и так далее и все только храня суффиксы, которых гораздо меньше, чем подстрок.
(16) не совсем так. Like ЧтоТо% очень хорошо в индекс попадет. А вот, если поставить % в начало, то без вариантов индекс будет сканироваться.
(14) у Вас в условии ПОДОБНО % в начале. Не важно есть индекс или нет, поиска не будет 100%
(18) по одному полю с «ИЛИ» 1С нормально ищет в индексе
(89) Если я правильно понял, вы ищете объяснение почему
То есть в ваших экспериментах (на «практике») как будто бы получается, что индекс каким-то волшебным образом ускоряет не поиск по началу строки — шаблону типа 1%, как должен в теории, но и по середине строки по шаблону %1% ускоряет тоже, хотя в теории не должен.
Предложу другое объяснение. Индекс — это файл, содержащий индексируемое поле. Он существенно меньше исходной таблицы. Часто помещается в оперативную память и остается в ней. По этому полный скан этого файла в поиске подстроки будет быстрее как раз настолько, насколько получилось у вас, чем сканирование основной таблицы. То есть не за счет каких-то хитрых структур данных или статистики (???). А за счет меньшего размера файла. А когда в теории говорится, что индекс ускоряет поиск по шаблону 1%, речь идет о более существенном ускорении, чем до 2-х секунд.
Это можно проверить. Будет интересно проверить тут же зависимость времени от длины подстроки в шаблоне %подстрока%. Зависимость должна быть. Чем длиннее строка, тем быстрее поиск.
(116)
Добрый день, Сергей. Да, в теории не должен. В плане не полный скан, а именно поиск в индексе, то есть seek. Мне кажется, просто этот оператор для like работает несколько иначе, чем просто перебор строк и разбор каждой на предмет соответствия условию. А вот как именно он это делает — это я уже не знаю.
(116)
Собственно, вот похожие ситуации описаны:
В обоих случаях пришли к выводу, что реальную работу выполняет Seek Predicate