Имя: Пароль:
1C
1C 7.7
v7: Ускорить поиск товара
0 evgpinsk_
 
07.09.19
09:35
Есть справочник ТМЦ
К нему есть подчинённый справочник "КодыТМЦПоставщиков"
http://prntscr.com/p2yhcx

Есть ТЗ (состоит из одного столбца "Код поставщика") заполняется списком пусть из 1000 строк.
Задача создать второй столбец "ТМЦ" , который будет находиться по "коду поставщика"

Решаю через перебор строк ТЗ и вызова для каждой строки функции:

Функция НайтиТМЦПоКоду(КодПоставщика)
    Спр_кодов=СоздатьОбъект("Справочник.КодыТМЦПоставщиков");
    Спр_прайсов=СоздатьОбъект("Справочник.ПрайсыПоставщиков");
    Спр_прайсов.НайтиПоКоду(ПрайсПставщика);
    Спр_кодов.ВыбратьЭлементыПоРеквизиту("Прайс",Спр_прайсов.ТекущийЭлемент(),0,1);
    Пока Спр_кодов.ПолучитьЭлемент()=1 цикл
        Если (Спр_кодов.Наименование=СокрЛП(КодПоставщика)) и (Спр_кодов.ПометкаУдаления()=0) тогда
            НайденныйТМЦ=Спр_кодов.ТекущийЭлемент().Владелец;
            Возврат 1;
        КонецЕсли;
    КонецЦикла;
    Возврат 0;
КонецФункции

Проблема, что для большого количества строк ТЗ заполнение второго столбца идёт очень долго.
Как ускорить?
1 Злопчинский
 
07.09.19
09:51
какой-то треш и угар
функцию для чего вызываете? для заполнения тз?
2 Злопчинский
 
07.09.19
09:52
вызываете в цикле?
верхний цикл тыща строк и для каждой строки тз акпкбор подчиненного справочника? еще бы не медленно
3 Злопчинский
 
07.09.19
09:53
создатьобъект - вынести за все циклы
4 Злопчинский
 
07.09.19
09:53
стукнись в скайп оперативно, посмотрю сделаем онлайн вместе
5 Злопчинский
 
07.09.19
09:56
даже в том коде который есть - судя по всему ты для каждого тмц перебираешь коды поставщиков для ВСЕХ тмц
6 Злопчинский
 
07.09.19
09:57
Впихни ИспользоватьРодителя(ТекущийТМЦ)
7 Злопчинский
 
07.09.19
10:00
Спр_кодов.ТекущийЭлемент().Владелец;
- убрать текущийэдемент.
когда у тебя есть открытая выборка по справочнику то при движении по ней ты уже имеешь доступ к строке справочника.
ипользуя текущийэлемент ты принрудительно заставляешь систему еще раз перечитать элемент справочника - нахрена?
8 Злопчинский
 
07.09.19
10:03
Спр_кодов.Наименование - хотя это строка 30 символов но система возвращает с обрезкой правых пробелов, но я бы на всякий случай влепитл бы СокрЛП
9 Сияющий в темноте
 
07.09.19
10:14
А почему искать по тз?
либо формекс и индексированная таблица либо внутренние представления в обьект Dictionary.
10 Злопчинский
 
07.09.19
10:20
да, итз - будет побыстрее. но на небольших обьемах и тз обычная норм.
а заполнение можно или чорным запросом сделать для начала или прямым запросом
11 Cthulhu
 
07.09.19
10:34
Функция НайтиТМЦПоКоду(КодПоставщика,ДляПрайса,Спр_кодов)
    Спр_кодов.ВыбратьЭлементыПоРеквизиту("Прайс",ДляПрайса,0,1); Пока Спр_кодов.ПолучитьЭлемент()
    <>0 Цикл Если (Спр_кодов.Наименование=СокрЛП(КодПоставщика))И(Спр_кодов.ПометкаУдаления()=0)
    Тогда Возврат(Спр_кодов.Владелец) КонецЕсли КонецЦикла; Возврат(0);
КонецФункции //НайтиТМЦПоКоду
Процедура Сформировать()
    Перем ДопустимЭтаТЗ,тПрайс,Спр_кодов;
    //ДопустимЭтаТЗ=СоздатьОбъект("ТаблицаЗначений");        // ну, допустим
    //ДопустимЭтаТЗ.НоваяКолонка("КодПоставщика");            // эта ТЗ заполнена
    //ДопустимЭтаТЗ.НоваяКолонка("Тмц","Справочник.ТМЦ");    // (хрензнаетсколькострок)
    тПрайс=СоздатьОбъект("Справочник.ПрайсыПоставщиков");
    тПрайс.НайтиПоКоду(ПрайсПставщика); тПрайс=тПрайс.ТекущийЭлемент();
    Спр_кодов=СоздатьОбъект("Справочник.КодыТМЦПоставщиков");
    ДопустимЭтаТЗ.ВыбратьСтроки(); Пока ДопустимЭтаТЗ.ПолучитьСтроку()<>0
    Цикл ДопустимЭтаТЗ.Тмц=НайтиТМЦПоКоду(ДопустимЭтаТЗ.КодПоставщика,тПрайс,Спр_кодов) КонецЦикла;
КонецПроцедуры
// а вообще - люто рекомендую замер производительности в отладчике!
12 zercv
 
07.09.19
10:36
ИМХО нужно смотреть на всю архитектуру, и начинать именно с нее.
Я лично несколько раз тоже начинал с "как ускорить функцию", хотя нужно с начало  начинать с архитектуры.
13 Злопчинский
 
07.09.19
10:59
код поставщика явно выбирается по нужному прайсу для текущей номенклатуры. не забудьте использоватьродителя
14 evgpinsk_
 
07.09.19
11:16
(12) Справочник ТМЦ, обычный всё понятно
Далее есть спарвочник "Прайсы". Грубо - теже поставщики
И далее, 3й справочник "КодыТМЦПоставщиков", скрин приводил в (0)

Для каждого товара есть несколько разных поставщиков и у каждого поставщика свой код товара.

Приходую товар по кодам поставщиков. В приходной накладной есть код поставщика. Мне нужно находить по коду свой ТМЦ из 1с
15 evgpinsk_
 
07.09.19
11:16
Спасибо за ответы, чуть позже перечитаю рекомендации выше
16 zercv
 
07.09.19
11:28
(14) если справочники подчиненные находи по нужному справочнику и бери просто владельца, либо выведи доп.реквизит с ссылкой на нужную ТМЦ.
У меня:
Справочник ТМЦ.
Справочник Поставщики.
Справочник АртикулПоставщика, подчиненный поставщику, в котором есть реквизит "ТМЦ" (ссылка на ТМЦ, к которому сопоставлен этот артикул).

В результате делаю поиск по "АртикулПоставщика" и нахожу нужный ТМЦ.
17 evgpinsk_
 
07.09.19
11:31
(16) Да, уже думал так переделать архитектуру. Но просто много чего накручено уже на текущую, переделки будет не мало.
18 evgpinsk_
 
07.09.19
11:32
(7) Перечитаю внимательно все рекомендации попозже )
Самоучка по 1с, и не все нюансы могу знать )
19 zercv
 
07.09.19
11:34
(17) не всегда долго переделывать :) (экспорт, импорт и т.д.)
Иногда долго надеяться и искать вариант решение того, что нужно просто переделать :-)
20 evgpinsk_
 
07.09.19
11:38
(19) Верно. Но если мой код можно оптимизировать и результат устроит, проще код оптимизировать
21 evgpinsk_
 
07.09.19
12:06
(11) Не совсем понял, чем ваш приведённый код отличается от моего?

Насколько я понимаю, основной тормоз идёт изза этого:
Спр_кодов.ВыбратьЭлементыПоРеквизиту("Прайс",ДляПрайса,0,1); Пока Спр_кодов.ПолучитьЭлемент()

Сейчас у меня: справочник ТМЦ - 35000 позиций
Справочник "КодыТМЦПоставщиков" - 23000 позиций
22 evgpinsk_
 
07.09.19
12:08
п.с. какбы понять, каким образом Миста форматирует иногда часть сообщений тегом [code]..[/code] ?
Предварительного просмотра вроде как нет здесь , что очень не удобно
23 Сияющий в темноте
 
07.09.19
12:19
(22) убедить Волшебника,чтобы код работал явно,а не по обнаружению слов,похожих на язык 1с.
24 evgpinsk_
 
07.09.19
12:30
(6) (13)
Не пойму где здесь может помочь ИспользоватьРодителя ?
25 Djelf
 
гуру
07.09.19
12:36
(21) Нет. Основной тормоз идет из-за
Если (Спр_кодов.Наименование=СокрЛП(КодПоставщика)) и (Спр_кодов.ПометкаУдаления()=0) тогда
Разберись со справочником чтобы пометки удаления и дубликатов вообще не было.
Тогда сможешь использовать НайтиПоНаименованию вообще без цикла.

Ну или прямой запрос сильно ускорит.
[code]
SELECT
Коды.PARENTEXT [ТМЦ :Справочник.ТМЦ]
FROM Справочник_КодыТМЦПоставщиков AS Коды
WHERE Коды.Прайс=@Прайс
AND Коды.DESCR=@Код
AND Коды.ISMARK<>'*'
LIMIT 1
[/code]

(24) Все верно, не поможет.
26 zercv
 
07.09.19
12:46
(25) при этом, если база скл, из-за сложной архитектуры и возможно долгой отроботке запроса, есть шанс нагрузить всю бд, в результате чего будет ошибка и закрытие приложение.
(0) долго это сколько?
27 Djelf
 
гуру
07.09.19
12:48
(26) Чего? оО Это элементарный запрос, попадающий в индекс. Он выполнится за 0.01с
28 evgpinsk_
 
07.09.19
13:09
(26) У меня идёт чтение из Excel файла, тоже не оптимизировано. Пока читаю Excel построчно через Лист2.Cells(i,j).value
Файл из 100 позиций - само чтение файла 18 секунд
Если в момент чтения ещё искать товары по артикулам поставщиков - то этот же файл 42 секунды.
29 evgpinsk_
 
07.09.19
13:17
(25) "Разберись со справочником чтобы пометки удаления и дубликатов вообще не было.
Тогда сможешь использовать НайтиПоНаименованию вообще без цикла. "

Дело в том, что Артикулы разных поставщиков могут пересекаться между собой. Пока не совсем понимаю, каким образом при моей текущий структуре можно обойтись только НайтиПоНаименованию.
Сейчас стурктуру 3х справочников изображу:
30 Djelf
 
гуру
07.09.19
13:33
(29) Точно. Так не получится. Что то я с sqlite уже навигационный поиск забываю ;)
Вот для поиска по Наименованию и пригодилось бы ИспользоватьВладельца, только местами нужно поменять ТМЦ и Прайс.
31 evgpinsk_
 
07.09.19
13:36
Структура сейчас такая /правда не совсем красиво писать структуру для 1с/:
http://prntscr.com/p3085x
Нужно подумать, имеет ли смысл менять архитектуру
32 evgpinsk_
 
07.09.19
13:39
(25) Не имел дело с прямыми запросами.  Я так понимаю нужно добавлять 1С++ ?
Имеет смысл тратить время на изучения для решения данной задачи?  )
33 Djelf
 
гуру
07.09.19
13:44
(32) dbf или sql?
Смысл имеет. В узких местах местах раз так в 1000 и более можно по скорости выиграть.
А 1С++ даже в "холостом" режиме за счет turbobl имеет смысл подключать.
34 evgpinsk_
 
07.09.19
13:45
(33) dbf
35 evgpinsk_
 
07.09.19
13:47
(33) Позволяю тратить на программирование только 10% своего рабочего времени, вспомнил что пытался внедрить 1с++, но както быстро он не зашёл )
Не хватило квалификации )

Хотя конечно ускориться в 1000 раз не помешало
36 evgpinsk_
 
07.09.19
13:51
(16) Т.е. в моём случае нужно поменять структуру следующим образом. Справочник "КодыПоставщик" исправить подчиние с текущего справочника "Номенклатура" на справочник "Прайсы"

http://prntscr.com/p30d76

Имеет смысл? Переделок в кодах будет много, много где завязано
37 evgpinsk_
 
07.09.19
13:57
Тогда сначала мы используем: КодыПоставщиков.ИспользоватьВладельца(Прайс)
т.е. отфильтровали все товары данного Поставщика

а затем через: КодыПоставщиков.НайтиПоНаименованию(АртикулаПоставщика,1,1)
найти нужный товар.

Это даст существенный выигрыш времени?
38 Djelf
 
гуру
07.09.19
14:26
(37) Да. Вместо 24с будет 24мс.
39 HawkEye
 
07.09.19
14:41
(0) что такое Прайс на скрине? строка? элемент Прайса?
40 HawkEye
 
07.09.19
14:43
+(39) судя по коду, элемент справочника Прайс..
41 evgpinsk_
 
07.09.19
14:44
(39) в первом посту скрин-ответ
(40) да
42 evgpinsk_
 
07.09.19
14:45
(38) Либо внедрить 1с++ и прямой запрос, так? ))
Нужно думать какой путь выбрать )
43 HawkEye
 
07.09.19
14:45
(41) значит получается, у тебя может быть несколько одинаковых кодов поставщика, относящихся к разным элементам Номенклатуры и что-бы разобрать к какому из них, используется справочник прайс, т.к. ты знаешь чей Прайс ты сейчас используешь...
44 HawkEye
 
07.09.19
14:47
+(43) а значит логичнее сначала найти все коды, а потом сравнивать прайсы т.к. кол-во элементов в прайсе в сотни раз больше одинаковых кодов, одно это (замена циклов местами) увеличит работу твоего кода раз в 100, при имеющейся архитектуре...
45 HawkEye
 
07.09.19
14:50
+(44) но есть проблема.... нет метода ВыбратьПоНаименованию() ))))
тогда можно запросом дернуть все коды поставщика с нужным тебе прайсом и засунуть результат в ТЗ, ДО цикла
а в цикле (точнее в твоей функции) искать нужный код в ТЗ....
46 HawkEye
 
07.09.19
14:52
(42) перепиши код по человечески и будет тебе приемлемая скорость работы без прямых запросов, 1С++ и переделывания архитектуры....
47 evgpinsk_
 
07.09.19
14:54
(43) " значит получается, у тебя может быть несколько одинаковых кодов поставщика, относящихся к разным элементам Номенклатуры"
нет, у поставщиков коды товаров уникальны.

" что-бы разобрать к какому из них, используется справочник прайс"
не совсем. Просто из логики введён справочник Прайс. Вместо него можно было бы например использовать справочник "Контрагенты"
48 HawkEye
 
07.09.19
14:54
+(45) либо добавь реквизит в КодыТМЦПоставщиков в которое запиши то-же самое что и в наименовании, чтоб можно было сформировать выборку по реквизиту
в коде сделай

Спр_кодов.ВыбратьЭлементыПоРеквизиту("КОДПОставщика",НужныйТебеКОд,0,1);
а в цикле сравнивай это нужный тебе прайс или нет...
49 HawkEye
 
07.09.19
14:56
(47) если кодПоставщика у тебя уникальный, на кой черт ты делаешь:
Спр_прайсов.НайтиПоКоду(ПрайсПставщика);
    Спр_кодов.ВыбратьЭлементыПоРеквизиту("Прайс",Спр_прайсов.ТекущийЭлемент(),0,1);?!

бред какой-то.. зная уникальный идентификатор запускать цикл по всему прайсу...

Спр_кодов.НайтиПоНаименованию(НужныйКод) - заменит вочти весь твой код из (0)
50 HawkEye
 
07.09.19
14:58
+(49) отдельное фи... пихать артикул в наименование... есть же реквизит "код" у которого уникальность отслеживается платформой....
51 evgpinsk_
 
07.09.19
14:59
(49) (50) Сейчас обдумаю )
52 HawkEye
 
07.09.19
15:00
(47) ты бы определился...
в (29): "Артикулы разных поставщиков могут пересекаться между собой"
в (47): "у поставщиков коды товаров уникальны."

когда правда то была?
53 evgpinsk_
 
07.09.19
15:02
(52) Есь два поставщика: Васыя и Петя.
У первого есть артикул товар "154222" в моей базе это Помидор
У второго есть артикул товар "154222" в моей базе это гвздь
54 evgpinsk_
 
07.09.19
15:03
Но в прайсе у Васи артикул "154222" уникален.
И в прайсе к Пети артикул "154222" тоже уникален.
55 HawkEye
 
07.09.19
15:04
(53) кого волнует что там у твоих поставщиков... мы так-то в твоей базе... и в твоей базе артикул ни разу не уникален...
56 evgpinsk_
 
07.09.19
15:06
(55) Я ответил просто на вопрос. Т.еуникальный индекс состоит из двух полей:
ПрайсПоставщика
Артикул
57 HawkEye
 
07.09.19
15:07
а если он не уникален, то варианта два:
1. в Справочник.КодыТМЦПоставщиков заводишь реквизит "АртикулПоставщтика" - заполняешь его, тем, что есть в наименовании...
потом в своей процедуре делаешь ВыбратьПоРеквизиту("АртикулПоставщтика", КодПоставщика)
потом сравниваешь с прайсом, прайс не мешало бы найти ДО попадания в свою функцию... ОДИН раз для всех строк...

2. вариант, запросо (или перебором) формируешь ТЗ по прайсу, а в свой функции ищешь в ТЗ...
58 evgpinsk_
 
07.09.19
15:07
(49) "Спр_кодов.НайтиПоНаименованию(НужныйКод) - заменит почти весь твой код из (0)"
т.е. решение должно быть такое:
я фильтрую свой справочник по Наименование/АртикулуПостащика/ - получу одну или несколько строк, и потом циклом в них проверяю на совпадени Прайсов/Поставщиков.

неужели так просто , сейчас обмазгую
59 HawkEye
 
07.09.19
15:08
(56) в том-то и дело, что когда приходишь за помощью, надо отвечать на те вопросы которые тебе задают, а не на те, которые в твоей голове звучат...
60 evgpinsk_
 
07.09.19
15:10
(59) Да вроде старался отвечать )
(52) - здесь нет противоречия вроде как
61 Djelf
 
гуру
07.09.19
15:18
(42) Не 1с++, там фоксовкий провайдер, удобнее 1sqlite http://catalog.mista.ru/public/559826/
Да и внедрять то особенно нечего...


Перем База;
Перем ЗапросПоКоду;

Процедура Инициализация()
    ЗагрузитьВнешнююКомпоненту("1sqlite.dll");
    База=СоздатьОбъект("SQLiteBase");
    База.Открыть(":memory:");
    ТекстЗапроса="
    |SELECT
    |    Коды.PARENTEXT [ТМЦ :Справочник.ТМЦ]
    |FROM Справочник_КодыТМЦПоставщиков AS Коды
    |WHERE Коды.DESCR=@Код
    |AND Коды.ISMARK<>'Коды'
    |AND Коды.Прайс=@Прайс
    |LIMIT 1
    |";
    ЗапросПоКоду=База.НовыйЗапрос();
    ЗапросПоКоду.Подготовить(ТекстЗапроса);
КонецПроцедуры

Функция  НатиПоКоду(Прайс,Код)
    ЗапросПоКоду.УстановитьПараметр("@Прайс",Прайс);
    ЗапросПоКоду.УстановитьПараметр("@Код",Код);
    Возврат ЗапросПоКоду.Выполнить(0);
КонецФункции

62 evgpinsk_
 
08.09.19
01:51
(57) Всё получилось по 1му варианту. Скорость в 10ки раз стала выше