|
Помогите оптимизировать код. | ☑ | ||
---|---|---|---|---|
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) По хорошему, надо Дату и Кондуктора добавить в поля выборки, т.к. по ним надо джойнить потом.
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |