|   |   | 
| 
 | Помогите оптимизировать код. | ☑ | ||
|---|---|---|---|---|
| 0
    
        Temdj 17.02.15✎ 14:53 | 
        Здравствуйте.
 Заранее извиняюсь за оформление поста. Код заполняет документ из табличной части обработки, которая заполняется из DBF файла. Код работает, но нестабильно, периодически выскакивают ошибки блокировки, в связи с чем (очень глупо) была добавлена обработка исключений. Выяснилось, что пропускаются некоторые строчки из ТЧ. Как реализовать по другому не пойму... Что с ним можно сделать? КОД: Для каждого СтрокаТЧ из ТЧ цикл Попытка НачатьТранзакцию(); СтрокаДата = Cтрока(Формат(Дата(СтрокаТЧ.DATE),"ДФ=dd.MM.yyyy")) + " " + СтрокаТЧ.TIME; ДатаВремя = Дата(СтрокаДата); Сотрудник = Справочники.СотрудникиОрганизаций.НайтиПоКоду(Лев(СтрокаТЧ.CONDUCTOR,4)); НомерМарш = СокрЛП(СтрокаТЧ.ROUTE_NUM); ПутевойЛист = ПолучитьПутевойЛист(Сотрудник, НомерМарш, ДатаВремя); Запрос = Новый Запрос("ВЫБРАТЬ | уатВыручкаВодителей.Ссылка |ИЗ | Документ.уатВыручкаВодителей КАК уатВыручкаВодителей |ГДЕ | уатВыручкаВодителей.ПутевойЛист = &ПутевойЛист"); Запрос.УстановитьПараметр("ПутевойЛист", ПутевойЛист); Результат = Запрос.Выполнить(); Если Результат.Пустой() тогда Запрос_2 = Новый Запрос("ВЫБРАТЬ | уатВыручкаВодителей.Ссылка |ИЗ | Документ.уатВыручкаВодителей КАК уатВыручкаВодителей |ГДЕ | уатВыручкаВодителей.Терминал = &Терминал | И уатВыручкаВодителей.Сотрудник = &Сотрудник | И уатВыручкаВодителей.ПутевойЛист = &Пустая | И уатВыручкаВодителей.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания"); Запрос_2.УстановитьПараметр("Терминал", СокрЛП(СтрокаТЧ.TRM_ID)); Запрос_2.УстановитьПараметр("Сотрудник", Сотрудник); Запрос_2.УстановитьПараметр("Пустая", Документы.уатПутевойЛист.ПустаяСсылка()); Запрос_2.УстановитьПараметр("ДатаНачала", НачалоДня(ДатаНачала)); Запрос_2.УстановитьПараметр("ДатаОкончания", КонецДня(ДатаОкончания)); Результат_2 = Запрос_2.Выполнить(); Если Результат_2.Пустой() тогда Документ = Документы.уатВыручкаВодителей.СоздатьДокумент(); уатОбщегоНазначенияТиповые.ЗаполнитьШапкуДокумента(Документ, глЗначениеПеременной("глТекущийПользователь")); Документ.Дата = КонецДня(ДатаВремя); Документ.Сотрудник = Сотрудник; Документ.Водитель = ПутевойЛист.Водитель1; Документ.Терминал = СтрокаТЧ.TRM_ID; Документ.ПутевойЛист = ПутевойЛист; Иначе Выборка_2 = Результат_2.Выбрать(); Выборка_2.Следующий(); Документ = Выборка_2.Ссылка.ПолучитьОбъект(); КонецЕсли; Иначе Выборка = Результат.Выбрать(); Выборка.Следующий(); Документ = Выборка.Ссылка.ПолучитьОбъект(); КонецЕсли; НоваяСтрока = Документ.РасшифровкаТранзакций.Добавить(); НоваяСтрока.Билет = Справочники.уатБилеты.НайтиПоКоду(СтрокаТЧ.PRTYPE); НоваяСтрока.Количество = 1; НоваяСтрока.Сумма = Число(СокрЛП(СтрокаТЧ.TARIF))/100; НоваяСтрока.НомерРейса = СтрокаТЧ.N_REIS; Если СокрЛП(СтрокаТЧ.TTYPE) = "2" тогда НоваяСтрока.Маршрут = ПолучитьМаршрутТроллейбуса(СтрокаТЧ.ROUTE_NUM); ИначеЕсли СокрЛП(СтрокаТЧ.TTYPE) = "1" тогда НоваяСтрока.Маршрут = ПолучитьМаршрутАвтобуса(ПутевойЛист,СтрокаТЧ.ROUTE_NUM); КонецЕсли; Документ.РасшифровкаТранзакций.Свернуть("Маршрут,Билет,НомерРейса","Количество,Сумма"); Документ.Количество = Документ.РасшифровкаТранзакций.Итог("Количество"); Документ.Сумма = Документ.РасшифровкаТранзакций.Итог("Сумма"); Документ.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный); ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); КонецПопытки; КонецЦикла; | |||
| 1
    
        H A D G E H O G s 17.02.15✎ 14:55 | 
        (0) Вынести запросы за транзакцию, как минимум.     | |||
| 2
    
        H A D G E H O G s 17.02.15✎ 14:56 | 
        (0) Прекратить писать копрокот.     | |||
| 3
    
        ShoGUN 17.02.15✎ 14:58 | 
        (0) А нафига в транзакции _читать_?     | |||
| 4
    
        ShoGUN 17.02.15✎ 15:00 | 
        А за запросы в цикле надо отрывать конечности.     | |||
| 5
    
        kosts 17.02.15✎ 15:02 | 
        За вот это положен пожизненных эцих с гвоздями
 
 | |||
| 6
    
        ShoGUN 17.02.15✎ 15:03 | 
        (5) Это наименьшее из зол, это просто кривовато. А вот запросы в цикле и чтение в транзакции - АДЪ.     | |||
| 7
    
        kosts 17.02.15✎ 15:05 | 
        (6) А ничего, что сотрудники могут иметь один и тот же код...
 Пример - периодически принимаемые/увольняемые... | |||
| 8
    
        ShoGUN 17.02.15✎ 15:10 | 
        (7) А ничего, что этот код выполняется в "КоличествоСтрок" раз медленней, чем мог бы?     | |||
| 9
    
        kosts 17.02.15✎ 15:14 | 
        (8) Уж лучше он в 100 раз медленнее работает, чем не правильно.
 Оптимизация неправильно работающего алгоритма бессмысленна. Если, что я не против оптимизации. | |||
| 10
    
        ShoGUN 17.02.15✎ 15:16 | 
        (9) Ну начнём с того, что ты не знаешь, правильно код работает, или нет, поскольку мы не знаем, какая это конфигурация. Может коды в справочнике "сотрудники" и не повторяются. А вот скорость у него однозначно никакая, вне зависимости от.     | |||
| 11
    
        Temdj 17.02.15✎ 15:17 | 
        (4) Полностью согласен, но не могу понять как по другому искать нужные документы.
 (5) Там по табельному номеру, это нормально, имхо. (7) Ну тут либо есть сотрудник, либо его нет - конфа такая... Ну или я её так понял... (8) Это отвратительно не приятно, но по этому я и обратился сюда... | |||
| 12
    
        Temdj 17.02.15✎ 15:17 | 
        (10) Период в день 10 мин примерно..     | |||
| 13
    
        ShoGUN 17.02.15✎ 15:21 | 
        (11) Опиши словами алгоритм, сначала. Почётче, желательно.     | |||
| 14
    
        kosts 17.02.15✎ 15:21 | 
        (10) >Документ.уатВыручкаВодителей КАК уатВыручкаВодителей
 Это показывает на УАТ Рарус. Смотрим Справочник сотрудники->Контроль уникальности отсутствует. | |||
| 15
    
        ShoGUN 17.02.15✎ 15:23 | 
        (14) Завидую вашим телепатическим способностям :) У меня нет УАТ, чтобы посмотреть.     | |||
| 16
    
        Зеленый пень 17.02.15✎ 15:24 | 
        (0) "Выяснилось, что пропускаются некоторые строчки из ТЧ." - значит надо выяснить, что не так конкретно с этими строчками.
 Код в целом "стабильный". | |||
| 17
    
        kosts 17.02.15✎ 15:28 | 
        (0) Сделай замер производительности, посмотри, где основной затык.     | |||
| 18
    
        Temdj 17.02.15✎ 15:32 | 
        код с комментариями.
 (16) Причина в конфликтах блокировок. Функция ЗагрузитьДанные() Экспорт //Очистим все документы с выручкой терминалов за выбраный период ОчиститьДокументы(); //Обработаем кажду строчку, все колонки имеют примитивные типы число, строка, булево. Для каждого СтрокаТЧ из ТЧ цикл Попытка //соберем дату приема выручки из колонки даты и колонки времени СтрокаДата = Строка(Формат(Дата(СтрокаТЧ.DATE),"ДФ=dd.MM.yyyy")) + " " + СтрокаТЧ.TIME; ДатаВремя = Дата(СтрокаДата); //Определим Сотрудника, маршрут и найдем путевой лист. Сотрудник = Справочники.СотрудникиОрганизаций.НайтиПоКоду(Лев(СтрокаТЧ.CONDUCTOR,4)); НомерМарш = СокрЛП(СтрокаТЧ.ROUTE_NUM); ПутевойЛист = ПолучитьПутевойЛист(Сотрудник, НомерМарш, ДатаВремя); //соберем все документы выручки по этому путевому листу Запрос = Новый Запрос("ВЫБРАТЬ | уатВыручкаВодителей.Ссылка |ИЗ | Документ.уатВыручкаВодителей КАК уатВыручкаВодителей |ГДЕ | уатВыручкаВодителей.ПутевойЛист = &ПутевойЛист"); Запрос.УстановитьПараметр("ПутевойЛист", ПутевойЛист); Результат = Запрос.Выполнить(); //Если нет таких документов проверим не появился ли документ с выручкой без путевого листа //вся нам выручка нужна, вся нам выручка важна. Если Результат.Пустой() тогда Запрос_2 = Новый Запрос("ВЫБРАТЬ | уатВыручкаВодителей.Ссылка |ИЗ | Документ.уатВыручкаВодителей КАК уатВыручкаВодителей |ГДЕ | уатВыручкаВодителей.Терминал = &Терминал | И уатВыручкаВодителей.Сотрудник = &Сотрудник | И уатВыручкаВодителей.ПутевойЛист = &Пустая | И уатВыручкаВодителей.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания"); Запрос_2.УстановитьПараметр("Терминал", СокрЛП(СтрокаТЧ.TRM_ID)); Запрос_2.УстановитьПараметр("Сотрудник", Сотрудник); Запрос_2.УстановитьПараметр("Пустая", Документы.уатПутевойЛист.ПустаяСсылка()); Запрос_2.УстановитьПараметр("ДатаНачала", НачалоДня(ДатаНачала)); Запрос_2.УстановитьПараметр("ДатаОкончания", КонецДня(ДатаОкончания)); Результат_2 = Запрос_2.Выполнить(); КонецЕсли; //получим/создадим документ выручки Если НЕ Результат.Пустой() тогда Выборка = Результат.Выбрать(); Выборка.Следующий(); НачатьТранзакцию(); Документ = Выборка.Ссылка.ПолучитьОбъект(); ИначеЕсли Не Результат_2.Пустой() тогда Выборка_2 = Результат_2.Выбрать(); Выборка_2.Следующий(); НачатьТранзакцию(); Документ = Выборка_2.Ссылка.ПолучитьОбъект(); Иначе НачатьТранзакцию(); Документ = Документы.уатВыручкаВодителей.СоздатьДокумент(); уатОбщегоНазначенияТиповые.ЗаполнитьШапкуДокумента(Документ, глЗначениеПеременной("глТекущийПользователь")); Документ.Дата = КонецДня(ДатаВремя); Документ.Сотрудник = Сотрудник; Документ.Водитель = ПутевойЛист.Водитель1; Документ.Терминал = СтрокаТЧ.TRM_ID; Документ.ПутевойЛист = ПутевойЛист; КонецЕсли; //Заполним ТЧ документа по строке ТЗ НоваяСтрока = Документ.РасшифровкаТранзакций.Добавить(); НоваяСтрока.Билет = Справочники.уатБилеты.НайтиПоКоду(СтрокаТЧ.PRTYPE); НоваяСтрока.Количество = 1; НоваяСтрока.Сумма = Число(СокрЛП(СтрокаТЧ.TARIF))/100; НоваяСтрока.НомерРейса = СтрокаТЧ.N_REIS; Если СокрЛП(СтрокаТЧ.TTYPE) = "2" тогда НоваяСтрока.Маршрут = ПолучитьМаршрутТроллейбуса(СтрокаТЧ.ROUTE_NUM); ИначеЕсли СокрЛП(СтрокаТЧ.TTYPE) = "1" тогда НоваяСтрока.Маршрут = ПолучитьМаршрутАвтобуса(ПутевойЛист,СтрокаТЧ.ROUTE_NUM); КонецЕсли; Документ.РасшифровкаТранзакций.Свернуть("Маршрут,Билет,НомерРейса","Количество,Сумма"); Документ.Количество = Документ.РасшифровкаТранзакций.Итог("Количество"); Документ.Сумма = Документ.РасшифровкаТранзакций.Итог("Сумма"); Документ.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный); //Закроем транзакцию ЗафиксироватьТранзакцию(); Исключение //тут надо бы ввести описание ошибки и сообщить об этом. ОтменитьТранзакцию(); КонецПопытки; КонецЦикла; КонецФункции | |||
| 19
    
        hhhh 17.02.15✎ 15:36 | 
        //тут надо бы ввести описание ошибки и сообщить об этом. 
 дык выведите описание ошибки, покажите. | |||
| 20
    
        ShoGUN 17.02.15✎ 15:43 | 
        (18) Во-первых, запросы лучше вынести из попытки, но это мелочи. Чтобы не было ошибок с правами(а вдруг?) - можно использовать ВЫБРАТЬ РАЗРЕШЕННЫЕ.
 Во-вторых - либо получи таблицу всех доков выручки за период(И связанных с путевыми листами, и несвязанных), и в ней ищи по своим условиям, либо помести свою ТЧ во временную таблицу и вместо условий работай JOIN-ами. | |||
| 21
    
        ShoGUN 17.02.15✎ 15:45 | 
        +(20) Смысл в том, чтобы получить один запрос и один результат запроса, и с ним работать, вместо цикла с запросами и работой с каждым результатом по отдельности.     | |||
| 22
    
        Зеленый пень 17.02.15✎ 15:52 | 
        (18) Метод борьбы с блокировками один - накладывать свои (в режиме управляемых блокировок, конечно).     | |||
| 23
    
        Temdj 17.02.15✎ 16:05 | 
        (21) Это я понимаю. Как реализовать не знаю.
 "вместо условий работай JOIN-ами" - что значит? Можно пример? | |||
| 24
    
        ShoGUN 17.02.15✎ 16:09 | 
        (23) Боюсь, пример будет не очень понятным. Приведи ещё функцию ПолучитьПутевойЛист, если можно.     | |||
| 25
    
        Temdj 17.02.15✎ 16:16 | 
        (24) Здесь в DBF может висеть либо водитель или кондуктор, по этому я сначала смотрю по кондуктору, а потом по водителю. 
 Функция ПолучитьПутевойЛист(Кондуктор, НомерМаршрута, ДатаОплаты) Запрос = Новый Запрос("ВЫБРАТЬ РАЗЛИЧНЫЕ | уатПутевойЛистЗадание.Ссылка |ИЗ | Документ.уатПутевойЛист.Задание КАК уатПутевойЛистЗадание |ГДЕ | уатПутевойЛистЗадание.Ссылка.Сотрудник1 = &Кондуктор | И уатПутевойЛистЗадание.Ссылка.Дата МЕЖДУ &Дата1 И &Дата2"); Запрос.УстановитьПараметр("Дата1", НачалоДня(ДатаОплаты)); Запрос.УстановитьПараметр("Дата2", КонецДня(ДатаОплаты)); Запрос.УстановитьПараметр("Кондуктор",Кондуктор); Результат = Запрос.Выполнить(); Если Результат.Пустой() тогда Запрос = Новый Запрос("ВЫБРАТЬ РАЗЛИЧНЫЕ | уатПутевойЛистЗадание.Ссылка |ИЗ | Документ.уатПутевойЛист.Задание КАК уатПутевойЛистЗадание |ГДЕ | уатПутевойЛистЗадание.Ссылка.Водитель1 = &Кондуктор | И уатПутевойЛистЗадание.Ссылка.Дата МЕЖДУ &Дата1 И &Дата2"); Запрос.УстановитьПараметр("Дата1", НачалоДня(ДатаОплаты)); Запрос.УстановитьПараметр("Дата2", КонецДня(ДатаОплаты)); Запрос.УстановитьПараметр("Кондуктор",Кондуктор); Результат = Запрос.Выполнить(); КонецЕсли; Выборка = Результат.Выбрать(); Пока Выборка.Следующий() цикл Возврат Выборка.Ссылка; КонецЦикла; КонецФункции | |||
| 26
    
        Temdj 17.02.15✎ 16:25 | 
        +(25) его лучше не смотреть... Ибо стыдно.     | |||
| 27
    
        ShoGUN 17.02.15✎ 16:28 | 
        (25) Бить тебя надо за такие функции.
 Мне тяжко такое без конфы и конструктора писать, если время терпит - вечером могу сесть написать хотя бы пример. | |||
| 28
    
        Лефмихалыч 17.02.15✎ 16:30 | 
        повезло троллейбусному депо...     | |||
| 29
    
        kosts 17.02.15✎ 16:32 | 
        У тебя в нескольких местах проверка на пустую выборку и новый запрос. Возможно будет лучше делать за один запрос. 
 Запрос из (25) примерно так. Но думаю основной тормоз это из-за записи документов. 
 | |||
| 30
    
        kosts 17.02.15✎ 16:33 | 
        (29) + Упорядочить по порядку     | |||
| 31
    
        ShoGUN 17.02.15✎ 16:36 | 
        (29) По хорошему, надо Дату и Кондуктора добавить в поля выборки, т.к. по ним надо джойнить потом.     | 
 
 | Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |