Имя: Пароль:
1C
1C 7.7
v7: Оптимизировать процедуру 1c7.7_SQL
0 _traktor_
 
02.10.23
22:37
Обьем базы 9 гб
Сервер: SQL2008+Server2016(ram64Gb+RAID10)+LAN_1GB
Клиенты: i5+ram8Gb

Достаточно долгое формирование обработки, более 10 минут.
https://cloud.mail.ru/public/3u7V/9z6yuyqKg
Какие варианты оптимизации кода ?
1 Злопчинский
 
02.10.23
22:48
тебе забесплатно отрефакторить/переписать?
.
вариант оптимизации самый первый если владеешь - прямые запросы.
.
10 минут ни о чем не говорит. что в итоге этих 10 минут получается? простыня на 100 тыс строк?
2 Злопчинский
 
02.10.23
22:49
штатно тоже можно ускорить, но надо СМОТРЕТЬ ПРЕДМЕТНО если нужен хороший результат.
3 Злопчинский
 
02.10.23
22:50
О... это еще на бухкомпоненте...
4 Харлампий Дымба
 
02.10.23
22:51
Круть. А кто-нибудь помнит что означали {} в условии запроса ? Это 7.0 или 7.5 было.
Сейчас попробую чуть-чуть посмотреть, без советов переписать всё на прямые запросы.
5 Злопчинский
 
02.10.23
22:54
занятная конструкция, никогда не использовал...
Условие ({СокрЛП(ВыбАртикул)} в СокрЛП(Артикул))
.
почему не тупо на равенство строк?
6 Злопчинский
 
02.10.23
22:56
(4) я вообще хз что такое с фигурными скобками в части синтаксиса запросов, никогда не юзал
7 Злопчинский
 
02.10.23
23:00
(0) Попробовать: все переменные запроса если они не используются в группировках/условиях - убрать. В коде их дергать через точку там где они нужны.
8 Злопчинский
 
02.10.23
23:02
Группировка Товар Без групп;
в коде убрать проверки Запрос.Товар.ЭтоГруппа()=1
9 Злопчинский
 
02.10.23
23:04
Многоэтажную хрень если и циклов с анализом флажков группировок переделать нахрен по образу и подобию как в ТиС список значений группировок (Отчет ОстаткиТМЦ), разбираться в этой лапше совсем не хочется
10 Злопчинский
 
02.10.23
23:07
Убрать нахрен консруктцию Таб.ПрисоединитьСекцию - это тормозная штука при выводе очета. Проще сделать два макета - с короткой строкой и с длинной строкой и задавать исходный макет в зависимости от флажков.
11 Злопчинский
 
02.10.23
23:08
Убрать работу с областями, это тоже тормозная штука.
оформит сразу как надо - даже если попроще пусть убдет
                                                Обл = Таб.Область(НачСтрока,7);    
Обл.РамкаСправа(3);
12 Злопчинский
 
02.10.23
23:10
ну и хорошо бы привести пример замера, на чем жрется время
13 Злопчинский
 
02.10.23
23:13
хз что там у вас в
ПолучитьЦенуТМЦ()
если периодика там дергается - то и тут тормоза будут, особенно если таких операций много или переписывать или переходить на объект "Периодический" - дает прирост при работе в периодическими реквизитами ~25%
14 Злопчинский
 
02.10.23
23:15
чисто приколоться.. надо было еще сложнее написать..
.
//*******************************************
Процедура ПриВыбреМестаХранения()
    Если МестоХранения.Выбран() = 0 Тогда
        Форма.ПоСкладам.Видимость(1);
    Иначе
        Форма.ПоСкладам.Видимость(0);
    КонецЕсли;
КонецПроцедуры
.
Форма.ПоСкладам.Видимость(1-МестоХранения.Выбран());
15 Злопчинский
 
02.10.23
23:20
в ВыбТовары = Только товары, группы не класть и попробовать вместо
"Условие (Товар в {ВыбТовары});"
.
условие убрать
фильтровать при обходе группировки по товарам по типу
Если ВыбТовары.НайтиЗначение(Запрос.Товар)=0 Тогда Продолжить; КонецЕсли;
.
может получиться охеренный итоговый прирост скорости выполнения
16 Злопчинский
 
03.10.23
10:28
на сем мое волонтерсов закончилось. думать влом.
Харлампий Дымба накинет еще, может и отчет перепишет.. он такой..
17 Харлампий Дымба
 
02.10.23
23:35
Всё ниже - моё мнение, пусть меня поправят, если  не прав.
Все вот такие условия в запросе:
"Условие (ПустаяСтрока(ТоварнаяГруппа)=0);"
плохи вызовом функций 1С, лучше задать
ПустаяТоварнаяГруппа=ПолучитьПустоеЗначение("Справочник.ТоварныеГруппы")
и в условии писать
Условие (ТоварнаяГруппа<>ПустаяТоварнаяГруппа);

Все вот такие условия
Условие(Товар.ВидНоменклатуры = ВидНоменклатуры)
хуже чем
ВидНоменклатурыТовара    = Регистр.ОстаткиТоваров.Номенклатура.ВидНоменклатуры;
Условие(ВидНоменклатурыТовара = ВидНоменклатуры)

Если в группировках - элементы справочник, а группы не нужны - пиши "Группировка Склад без групп"
если не важен порядок и не планируешь испоьзовать потом наименование элементов из группировки - пиши "Группировка Склад без групп без Упорядочивания", если планируешь использовать наименование Упорядочить по Склад.Наименование

Запрос.Товар.ЭтоГруппа() плохо тем, что ты впустую считываешь объект из базы (он тебе дальше не нужен) -
пиши Запрос.ЭтоГруппа("Товар")

ПолучитьЦенуТМЦ(Запрос.Товар,ДатаОтчета) - не вижу что в коде, но очень подозреваю, что там что-то типа
Товар.Цена.Получить(ДатаОтчета)
лучше переписать
гл_П1.ИспользоватьОбъект("Цена",Товар);
Возврат гл_П1.ЗначениеНаДату(НаДату);
где глП_1 - глобальная переменная, которая инициализируется в глобальном модуле (не в функции ПолучитьЦенуТМЦ!), т.е. в конце глобального модуля
П=СоздатьОбъект("Периодический");

В макете отчета не пиши
Запрос.Товар.Наименование
во-первых используй уже подготовленную переменную, а в ячейку пиши уже ее
ПечТовар=Запрос.Товар.Наименование
в группировке в запросе напиши Упорядочить По Товар.Наименование
а ячейке присваивай
ПечТовар=Запрос.ЗначениеУпорядочивания(1)
либо в запросе сразу делай переменную
АртикулТовара=Запрос.Товар.Артикул
и пиши
ПечАртикул=Запрос.АртикулТовара

Запрос.Товар.Цвет.Наименование - ооооочень долго

перепиши все так, чтобы по возможности не было
Реквизит=Запрос.ЭлементСправочника.РеквизитСправочника
если нельзя обойтись без этого, тогда хотя бы так:
Элемент=Запрос.ЭлементСправочника;
Реквизит=Элемент.РеквизитСправочника;

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

можно в принципе и текст запроса составлять так, чтобы не получать лишних реквизитов - если не поставили группировку или отбора по складу - то
Склад    = Регистр.ОстаткиТоваров.МестаХранения;
можно убирать

по бухитогам вопросов нет

Воспользуйся замером производительности в отладчике - включи часы в начала отчета, выключи после окончания, посмотри время

Это основное, что ты можешь выжать из обычных 1совских отчетов
18 Харлампий Дымба
 
02.10.23
23:37
(16) Хехе - чуть не один в один)
19 Злопчинский
 
02.10.23
23:41
(18) а что делать... Если в руках молоток - весь мир состоит из гвоздей...
20 Djelf
 
гуру
03.10.23
11:46
(6) На ИТС есть описание фигурных скобок: https://its.1c.ru/db/metod8dev/content/2511/hdoc
(0) Попробуй Запрос.ВключитьSQL(0);
Смутно помнится, что на тупящих запросах на sql базах это помогало.
21 Харлампий Дымба
 
03.10.23
10:54
(20) Это про скобки в 8. В 7.7 же, насколько помнится, скобки  остались как анахронизм от версии 7.0 - ими предполагалось выделять переменные модуля, используемые в запросе, в отличие от переменных запроса. А в 7.0 они попали так как широко использовались в 6.0 для указания макроимени (ссылки) субконто типовой операции..
К 7.7 решили, что скобки - лишнее, но синтаксис оставили для совместимости. Попробовал сейчас, думал что можно будет с помощью этих скобок иметь возможность использовать одинаковые имена для переменных запрос и модуля, типа "Условие (Товар в {Товар})", но нет, не работает. Так что скобки не нужны от слова "совсем".

(20) Запрос.ВключитьSQL(0) - как правило, наоборот резко замедляет скорость формирования запроса. Этот переключатель, чтобы сформировать запрос, не как sql-ный, а как dbf-ный. Использовался, видимо самой 1С, для отладки, чтобы понять не косячит ли sql-ный запрос и даёт ли те же данные, что и dbf-ный.
В некоторых случаях как раз и помогает обойти оставшиеся косяки sql-ных запросов, например
Условие (ДатаДок в СписокДат) в sql у меня не работает, а в DBF - без проблем. Поэтому надо или
Запрос.ВключитьSQL(0);
или
Условие (СписокДат.НайтиЗначение(ДатаДок)>0)
И второе всё равно работает гораздо быстрее.

(0) Ах да, ещё у тебя там "Группировка Партия" - убери для тех типов цен, где она не нужна. Тут хорошая прибавка будет.
Ну и в ТЗ в цикле группировки по партиям зачем пихать каждый раз .НоваяСтрока с тем же товаром? Чтоб потом делать ТЗ.Свернуть с миллионом строк? Лучше посчитай в цикле итоговую сумму по товару, и потом добавь в ТЗ одной строкой.
А вообще - "Замер производительности" и смотри на чем проигрываешь, может у тебя Запрос.Выполнить - 10% от времени, а остальное это неоптимальный алгоритм обработки полученных данных.
22 Djelf
 
гуру
03.10.23
11:36
(21) Ну да, для 8ки, но что-то схожее видимо есть..
В том то и дело что "как правило", попробовать все равно стоит.
23 Злопчинский
 
03.10.23
13:11
(21) Условие (ДатаДок в СписокДат) в sql у меня не работает
- проверь когда в списке одно значение и когда несколько
24 vladmenleo
 
03.10.23
13:27
(0) Переписать все на прямой запрос из 1с++. Лучше полчаса потерять, зато потом за 5 минут долететь (с)
25 Chai Nic
 
03.10.23
13:31
(24) +1
Черные запрос на sql часто работает неадекватно - вытягивает половину базы в temp в виде dbf-файлов и дальше обрабатывает уже их. Сталкивался с подобным отчетом по продажам, который формировался чуть ли не полчаса. Простой перебор документов был на несколько порядков быстрее.
26 Злопчинский
 
03.10.23
13:32
(25) это зависит от того как написаны условия. если "неправильно" - тогда тянется результат "запроса" в темп и на него дополнительно накатывают условия и потом выдают как результат "запроса"
27 Злопчинский
 
03.10.23
13:36
(26) .. хотя это я на дбф наблюдал, а вот как на скуле - хз...
28 vladmenleo
 
03.10.23
13:37
(26) Именно так, все от условий. Частенько оптимально засунуть результат во временную таблицу на сервере, а потом из нее выбрать по условию
29 vladmenleo
 
03.10.23
13:43
(26) Ступил, речь про черный запрос. Почти пять лет в конторе, все на прямых запросах
30 Chai Nic
 
03.10.23
13:52
(27) А на sql так же, только хуже))
31 Злопчинский
 
03.10.23
14:04
я столнулся с тем что на скуле
Условие(Номенклатура в Сзноменклатура);
- адски тормозило.
проще было собрать запрос без фильтра по товарам (даже если товаров было очень много)
и уже при обходе результат запроса фильтровать вручную через СЗНоменклатура.НайтиЗначение(Запрос.Номенклатура).
.
почему так - хз, может как-то криво секретный релиз поставлен или еще что...
32 АгентБезопасной Нацио
 
03.10.23
14:43
(25) ага, а все потому, что sql в клюшках используется как тупое таблицохранилище. поэтому оно, грубо говоря, тянет весь селект-лист на клиента в дбф (фильтруя только, емнип, по общим реквизитам доков), а уже там строит индексы для других отборов.
(24) категорически согласен.
33 Злопчинский
 
03.10.23
15:28
(24) (32) Ну дык и помогите страждущему ;-)
34 Arbuz
 
03.10.23
15:37
(24) В оригинале было:
Лучше день потерять, зато потом за 5 минут долететь (с)

Я не знаю как там на mssql обстоят дела, но прямые на dbf через 1sqlite у меня дают типичный выигрыш более двух порядков (я где-то отмечал, что в ТиС на запросе в СписаниеТМЦ я получил выигрыш в 8000 раз). Уже только это заставило меня не думать о чорных запросах совсем никогда. Не считая того, что в прямой запрос можно переложить значительную часть логики постобработки, что ещё ускоряет итог.

Бедные снеговиководы, через плечо заглядывая с неприкрытой жалостью и брезглиговостью на уродские клюшки, так и не могут поверить своим глазам, когда видят, что у меня средняя скорость проведения документа в потоке при очень активных юзерах < 70мс на оборудовании чья производительность уступает паре смарт-чайников. Есть, конечно, БП'шный снеговик куда всё консолидируется из клюшек - удобный, красивый, современный, упитанный, уверенный и лоснящийся.
35 Злопчинский
 
03.10.23
15:41
(34) я прямые не осилил, только самое простое. Просто надобности не было, не работал я в нагруженных системах с большим количеством пользователей, пичалька...
36 АгентБезопасной Нацио
 
03.10.23
16:16
(33)
"-Господи, ну помоги же Абраму выйграть в лотерею!
--Да я бы помог, но пусть он хоть раз купит лотерейный билет!"
©
Я в том смысле, что пусть хотя бы трассировку сделает, определит, где основные тормоза... а то накинул, и пропал..

Да и клюшек под рукой нет, проверить. Запрос-то и руками написать не проблема, но малейший косяк в синтаксисе - и будет бодяга на пару недель, судя по скорости реакции ТСа
37 vladmenleo
 
03.10.23
16:39
(33) (0) В первом приближении как-то так
ТзЗапрос = СоздатьОбъект("ТаблицаЗначений");
    ЗапросДляТЗ = СоздатьОбъект("ODBCRecordSet");
    ТекстЗапроса = "
    |Select
    |    Рег.МестаХранения as [Склад $Справочник.Склады],
    |    Тов.ID as [Товар $Справочник.Номенклатура],
    |    $Тов.Артикул as Артикул,
    |    $Тов.Рисунок as Рисунок,
    |    $Тов.ТоварнаяГруппа as [ТоварнаяГруппа $Справочник.ТоварныеГруппы], -- ????? Если это справочник
    |    Рег.Партии as Партия,
    |    Рег.КоличествоОстаток as КонКол,
    |    $Тов.КоэффПересчета as КоэфТук,
    |From                                                                                                                                  
    |    $РегистрОстатки.ОстаткиТоваров(:ДатаОтчета~,, " + ?(МестоХранения.Выбран()=0, "", "Рег.МестаХранения = :МестоХранения") + ") as Рег
    |Inner Join
    |    $Справочник.Номенклатура Тов WITH (NOLOCK) ON Тов.ID = Рег.Номенклатура
    |where 1 = 1
    |" + ?(ВыбТовары.РазмерСписка() > 0, "and Тов.ID in (Select Val From #СписокТоваров)", "")+ "
    |";
    ЗапросДляТЗ.УстановитьТекстовыйПараметр("ДатаОтчета", ДатаОтчета);
    ЗапросДляТЗ.УстановитьТекстовыйПараметр("МестоХранения", МестоХранения);
    ЗапросДляТЗ.УложитьСписокОбъектов(ВыбТовары,"#СписокТоваров", "Номенклатура");
    ТзЗапрос = ЗапросДляТЗ.ВыполнитьИнструкцию(ТекстЗапроса);
Дальше по аналогии добавить условий
38 vladmenleo
 
03.10.23
16:47
(34) Про оригинал согласен, но на прямой запрос переписать полчаса, ну час от силы. Зато потом на черные запросы смотреть не захочется
Пользователь не знает, чего он хочет, пока не увидит то, что он получил. Эдвард Йодан