|
v7: глВернутьЦену оптимизация | ☑ | ||
---|---|---|---|---|
0
lg2marvel
21.05.13
✎
01:53
|
Добрый день. Тормоза при выписке накладных привысили порог терпения. Надо что-то с этим делать. Конфигурация комплексная.
Погуглив пол дня пришел к выводу что делать нужно прямым запросом, перебор не прокатит. Единсвенный вариант который нашел был на Инфостате, но прикрутить его не получилось. Для начала хочу понять принцип действия. При подборе товара при его выборе будет каждый раз выполняться запрос, который будет возвращать цену для введенного товара и установленного типа цены. Вот только знаний в этой области негусто, подскажите что почитать и как оно правильнее будет. Спасибо всем откликнувшимся. |
|||
1
Базис
naïve
21.05.13
✎
02:08
|
Сейчас - спать, перед сном ещё раз подумать - утром в голове будет простое решение.
|
|||
2
Злопчинский
21.05.13
✎
03:15
|
||||
3
Злопчинский
21.05.13
✎
03:16
|
(0)
1.пользователей - в терминал. 2.выписку накладных проводить в ТА, а не в заднепроходном отверстии |
|||
4
Aleksey
21.05.13
✎
03:21
|
(3) а какая разница? у него глВернутьЦену тормозит - ибо это периодический реквизит
По хорошему нужно переписывать цены на регистры и будет летать |
|||
5
Злой Бобр
21.05.13
✎
04:16
|
(0) Я вот тоже хочу понять что у вас ... Но угадывать принципиально нехочу. Если хотите получить ответ - научитесь четко формулировать мысли и сам вопрос. А почитать можно много чего, Мопасана как вариант ...
(4) А у меня нетормозит, и тоже периодический. Что я делаю не так?.. |
|||
6
Mikeware
21.05.13
✎
05:51
|
(2) на инфосране есть метода замены на прямой запрос через класс ПрямойЗапрос.
+(4) лучше не на регистр, а на справочник - иначе групповое извлечение цен замедляется очень сильно. как вариант, кэшировать цены, если они меняются реже 1 раза в день. |
|||
7
Mikeware
21.05.13
✎
06:51
|
||||
8
orefkov
21.05.13
✎
07:08
|
(0)
Так тормоза при проведении или подборе? Имхо, начинать надо не с гугленья и не с прямых запросов, а с замеров производительности. Что они показали, кто сегодня слабое звено? |
|||
9
VladZ
21.05.13
✎
08:03
|
(0) Прямой запрос - это лучший вариант. Но есть и другой: ставим "Отбор по реквизиту" на реквизите "ТипЦен" в справочнике "Цены". В модуле функции меняем:
//ЦеныНоменклатуры.ВыбратьЭлементы(); ЦеныНоменклатуры.ВыбратьЭлементыПоРеквизиту("ТипЦен",НужныйТипЦен); // так будет быстрее!!! |
|||
10
Reaper_1c
21.05.13
✎
08:09
|
(8) Да ладно, у ТиС эта процедура - ахиллесова пята всей конфигурации...
|
|||
11
lg2marvel
21.05.13
✎
08:40
|
(5) У меня вот так:
Функция глВернутьЦену(Товар, КатегорияЦены, ДатаЦены=0, Валюта=0) Экспорт Цена = 0; ЦеныТовара = СоздатьОбъект("Справочник.Цены"); ЦеныТовара.ИспользоватьВладельца(Товар); ЦеныТовара.ВыбратьЭлементы(); Пока ЦеныТовара.ПолучитьЭлемент() = 1 Цикл Если ЦеныТовара.ПометкаУдаления() = 1 Тогда Продолжить; КонецЕсли; Если ЦеныТовара.КатегорияЦены = КатегорияЦены Тогда Цена = ЦеныТовара.ТекущийЭлемент(); Прервать; КонецЕсли; КонецЦикла; Если (Цена <> 0) И (ПустоеЗначение(ДатаЦены) = 0) Тогда // задана дата, значит, нужно вернуть числовое значение цены // определим, для какой единицы (по умолчанию для базовой) Единица = Цена.Единица.Получить(ДатаЦены); Коэффициент = 1; Если (ПустоеЗначение(Единица) = 0) И (Единица.Единица <> Товар.БазоваяЕдиница) Тогда // указана цена не для базовой единицы, учтем коэффициент Коэффициент = ?(Единица.Коэффициент = 0, 1, 1/Единица.Коэффициент); КонецЕсли; // определим валюты (по умолчанию пересчитываем в гривню) ВалН = Цена.Валюта.Получить(ДатаЦены); ВалК = ?(ПустоеЗначение(Валюта) = 1, Гривня, Валюта); // результат умножим на коэффициент Возврат Коэффициент * глПересчет(Цена.Цена.Получить(ДатаЦены),ВалН,ВалК,ДатаЦены); КонецЕсли; Возврат Цена; КонецФункции (8) Тормоза при подборе, замер производительности показал что глВернутьЦену выполняется при 14-16 пзизиях 0,6 сеунд, при увеличении количества позиций лидировать начинает контроль остатка. |
|||
12
Mikeware
21.05.13
✎
08:42
|
(11) цены можнои закэшировать, допустим, в индексированной ТЗ.
а остаток брать прямым запросом из регистра, на ТА. ну и работать, есссно, на ТА |
|||
13
Ёпрст
21.05.13
✎
09:24
|
Останки тоже надо закешировать при подборе.
|
|||
14
varelchik
21.05.13
✎
09:43
|
Держи.
Функция ВернутьЦену() Если ЭтоГруппа()=1 Тогда Возврат ""; КонецЕсли; ЗапросЦена.УстПараметр(1,ТекущийЭлемент()); Рез=ЗапросЦена.ВыполнитьСкалярный(); лЦена=Рез.Цена; лСкидка=Рез.Скидка; лНал=Рез.Нал; Если лСкидка=0 Тогда лЦена=лЦена-(лЦена*Скидка/100); Иначе лЦена=лЦена-(лЦена*лСкидка/100); КонецЕсли; Если ВидДокумента="ЗаявкаНаСчет" Тогда Если лНал=1 Тогда лЦена=лЦена*Константа.КоэфБезнал.Получить(РабочаяДата()); КонецЕсли; КонецЕсли; Возврат ?(лЦена=0,"",Формат(лЦена,"Ч12.2")); КонецФункции // ВернутьЦену |
|||
15
varelchik
21.05.13
✎
09:44
|
ТекстЦена="
|select |$ПоследнееЗначение.Контрагенты.Нал(:ВыбКонтрагент,:ВыбДата) Нал, |CASE |WHEN |$ПоследнееЗначение.Номенклатура.ФлагФиксСкидки(Цены.ParentExt,:ВыбДата)>0 |THEN $ПоследнееЗначение.Номенклатура.ФиксированнаяСкидка(Цены.ParentExt,:ВыбДата) |ELSE 0 END as Скидка, |$ПоследнееЗначение.Цены.Цена(Цены.id,:ВыбДата) as Цена |from $Справочник.Цены Цены (nolock) |WHERE Цены.ParentExt=? and $Цены.КатегорияЦены=:ВыбКатегория and Цены.ismark=0 |"; ЗапросЦена.ДобПараметр(1,14,9,0); ЗапросЦена.УстановитьТекстовыйПараметр("ВыбКонтрагент",Контрагент); ЗапросЦена.УстановитьТекстовыйПараметр("ВыбКатегория",КатегорияЦен); ЗапросЦена.УстановитьТекстовыйПараметр("ВыбДата",РабочаяДата()); Стат=ЗапросЦена.Подготовить(ТекстЦена); Если Стат=0 Тогда Сообщить(ЗапросЦена.ПолучитьОписаниеОшибки()); КонецЕсли; Это подготовка ЗапросЦена в процедуре ПриОткрытии(). |
|||
16
varelchik
21.05.13
✎
09:45
|
И ничего летает как самолет.
|
|||
17
varelchik
21.05.13
✎
09:47
|
Если надо с остатками то добавляем это:
ТекстОстаток=" |select |Рег.ОстатокТовараОстаток Ост |from $РегистрОстатки.ОстаткиТоваров(,,Товар=? and Фирма=? "+?(СписокСкладов.РазмерСписка()>0," and Склад IN (SELECT val FROM #Склады) ","")+",Товар) Рег |"; Если СписокСкладов.РазмерСписка()>0 Тогда ЗапросОстаток.УложитьСписокОбъектов(СписокСкладов,"#Склады","МестаХранения"); КонецЕсли; ЗапросОстаток.ДобПараметр(1,14,9,0); ЗапросОстаток.ДобПараметр(1,14,9,0); стат=ЗапросОстаток.Подготовить(ТекстОстаток); Если Стат=0 Тогда Сообщить(ЗапросОстаток.ПолучитьОписаниеОшибки()); КонецЕсли; И это Функция ОстатокПолный() Если ЭтоГруппа()=1 Тогда Возврат ""; КонецЕсли; ЗапросОстаток.УстПараметр(1,ТекущийЭлемент()); ЗапросОстаток.УстПараметр(2,Фирма); Рез=ЗапросОстаток.ВыполнитьСкалярный(); Возврат ?(Рез=0,"",Рез); КонецФункции // ОстатокПолный |
|||
18
lg2marvel
21.05.13
✎
10:06
|
(14) (15) (16) (17) Спасибо добрый человек, буду прикручивать
|
|||
19
Aleksey
21.05.13
✎
10:21
|
(6) а как на справочнике переодичность будешь делать? (P.S. он и так в типовой на справочнике)
|
|||
20
varelchik
21.05.13
✎
10:30
|
(18) НЕ забываем что для этого нужна еще компонента 1С++.
|
|||
21
varelchik
21.05.13
✎
10:31
|
Да и еще забыл.
Функция глСоединение(ТипСоединения="",ПутьИБ="",Пользователь="",Пароль="",ИмяСервера="") Экспорт Каталог=КаталогИБ(); Если Врег(ТипСоединения)="SQL" Тогда Попытка БД =СоздатьОбъект("ODBCDataBase"); Запрос=СоздатьОбъект("ODBCRecordSet"); Если ПустоеЗначение(ПутьИБ)=0 Тогда БД.ПрисоединитьИБ(ПутьИБ,Пользователь,Пароль); Запрос.УстБД(БД); КонецЕсли; Возврат Запрос; Исключение Возврат 0; КонецПопытки; ИначеЕсли Врег(ТипСоединения)="ОЛЕ" Тогда Попытка БД = СоздатьОбъект("OLEDBData"); Если ПустоеЗначение(ПутьИБ)=0 Тогда БД.ПрисоединитьИБ(ПутьИБ); Иначе СтрокаСоединения = "Provider=VFPOLEDB.1;Deleted=Yes;Data Source=" + Каталог + ";Mode=ReadWrite;Extended Properties="";User ID="";Password="";Mask Password=False;Collating Sequence=RUSSIAN;DSN=""";; БД.Соединение(СтрокаСоединения); КонецЕсли; Команда=БД.СоздатьКоманду(); Команда.УстановитьКаталогВремТаблиц(КаталогВременныхФайлов()); Возврат Команда; Исключение Возврат глСоединение("ДБФ",ПутьИБ); КонецПопытки; ИначеЕсли Врег(ТипСоединения)="ДБФ" Тогда Попытка БД =СоздатьОбъект("ODBCDataBase"); Если ПустоеЗначение(ПутьИБ)=0 Тогда БД.ПрисоединитьИБ(ПутьИБ); Иначе БД.Соединение("DRIVER={Microsoft Visual FoxPro Driver};Deleted=Yes; |Null=Yes;Collate=RUSSIAN;Exclusive=No;SourceType=DBF;SourceDB="+Каталог); КонецЕсли; Запрос=СоздатьОбъект("ODBCRecordSet"); Запрос.УстБД(БД); Возврат Запрос; Исключение Возврат 0; КонецПопытки; ИначеЕсли Врег(ТипСоединения)="SQLITE" Тогда база = СоздатьОбъект("SQLiteBase"); база.Открыть(":memory:"); Запрос = база.НовыйЗапрос(); Запрос.ВыполнитьЗапрос("PRAGMA journal_mode=WAL"); Возврат Запрос; ИначеЕсли Врег(ТипСоединения)="SQL_NEW" Тогда Попытка БД =СоздатьОбъект("ODBCDataBase"); Запрос=СоздатьОбъект("ODBCRecordSet"); СтрокаСоединения="Driver={SQL Server};Server="+ИмяСервера+";Database="+ПутьИБ+";Uid="+Пользователь+";Pwd="+Пароль+";"; Бд.Соединение(СтрокаСоединения); Запрос.УстБД(БД); Возврат Запрос; Исключение Возврат 0; КонецПопытки; Иначе МФ=СоздатьОбъект("MetaInfoClasses"); Если МФ.ЭтоSQL_Версия()=1 Тогда Возврат глСоединение("SQL"); Иначе Возврат глСоединение("SQLite"); КонецЕсли; КонецЕсли; КонецФункции // глСоединение |
|||
22
Ковычки
21.05.13
✎
10:34
|
Если (Цена <> 0) И (ПустоеЗначение(ДатаЦены) = 0) Тогда
перенеси в начало |
|||
23
Ковычки
21.05.13
✎
10:34
|
без цены
|
|||
24
lg2marvel
21.05.13
✎
11:12
|
(22) Дык как же, если Цена вычисляется в цикле
|
|||
25
Ёпрст
21.05.13
✎
11:13
|
(21) для оледб устаревшая строка соединения
|
|||
26
Ёпрст
21.05.13
✎
11:14
|
ну и твой код.. только для скуль версии, поентому эти строки соединения.. как бэ не уместны
|
|||
27
lg2marvel
21.05.13
✎
13:51
|
Погонял еще отладчиком, вижу такую ситуацию:
http://s001.radikal.ru/i193/1305/fb/ffef15834e05.jpg http://i023.radikal.ru/1305/bb/b14f4698ff44.jpg Это при 100 позициях в списке. Приоритет меняется кардинально. |
|||
28
lg2marvel
21.05.13
✎
13:52
|
||||
29
Ёпрст
21.05.13
✎
13:56
|
Константы надо всегда кешировать - это мегатормоз.
|
|||
30
Ёпрст
21.05.13
✎
13:57
|
+ избегать конструкций мо метаданным, типа глестьреквизит траляля
|
|||
31
varelchik
21.05.13
✎
14:00
|
(26) Согласен.
Ну это я так кинул, что человек понял что за объекты юзаются. |
|||
32
lg2marvel
21.05.13
✎
14:06
|
(29) Что вы имеете ввиду? Как ее можно кешировать?
|
|||
33
Ёпрст
21.05.13
✎
14:08
|
(32)
Перем МояСуперМуперКонстанта Экспорт; .... МояСуперМуперКонстанта = Константа.Дефчонки.Настёна; |
|||
34
Ёпрст
21.05.13
✎
14:09
|
в общем, константы, которые не меняются - в глобальнике присваивай переменным.. их потом и используй в коде, заместо того, чтоб обращаться каждый раз к 1sconst в коде
|
|||
35
lg2marvel
21.05.13
✎
14:19
|
Спасибо, при проверке константы теперь нет задержки.
Я присваивание значение константы переменной засунул в ПриНачалеРаботыСистемы(), куда ее лучше впихнуть? или же просто перед модулем? |
|||
36
Ёпрст
21.05.13
✎
14:19
|
(35) да там вполне покатит.
|
|||
37
Ёпрст
21.05.13
✎
14:20
|
тока смотри, у там как минимум, их 3 штуки
:) |
|||
38
Ёпрст
21.05.13
✎
14:21
|
Ну и останки на прямой запрос ИЛИ, получить все итоги при открытии подбора в ТЗ, затем в формулу - поиск в этой ТЗ, это в разы быстрее, чем Рег.Остаток
|
|||
39
Ёпрст
21.05.13
✎
14:21
|
Можно даже через ВыгрузитьИтоги регистра.
|
|||
40
lg2marvel
21.05.13
✎
14:24
|
(38) ааааааа мой мозг сейчас взорвется
Хачу научиться делать прямым запросом, но пока дальше подключения компонеты не добрался, перелопачиваю примеры. |
|||
41
varelchik
21.05.13
✎
15:07
|
(38) Но я бы посоветовал не в ТЗ а в ИндексированнуюТаблицу.
У нее скорость поиска(ты ж сам знаешь) в разы больше нем на ТаблицеЗначений. |
|||
42
Ёпрст
21.05.13
✎
15:09
|
(41) ну мот автору еще религия не позволяет ИТЗ использовать :)
|
|||
43
varelchik
21.05.13
✎
15:23
|
(42) Тем более остатки все таки луче параметрическим запросом брать.
Так они будут актуальными. |
|||
44
lg2marvel
21.05.13
✎
17:50
|
Не посоветуете конструктор запросов?
|
|||
45
Ёпрст
21.05.13
✎
17:52
|
У тя скль или дбф ?
|
|||
46
lg2marvel
21.05.13
✎
17:54
|
скль
|
|||
47
Aleksey
21.05.13
✎
18:01
|
(32)
В ГМ Перем глКэшКонстант Экспорт; // Список значений констант .... //***********************************************Кэширование*************************************** // получение константы если она есть то из кэша, иначе из базы Функция глКонстанта(Имя) Экспорт Значение = глКэшКонстант.Получить(Имя); Если ПустоеЗначение(Значение) = 1 Тогда Значение = Константа.ПолучитьАтрибут(Имя); глКэшКонстант.Установить(Имя,Значение); КонецЕсли; Возврат Значение; КонецФункции ... глКэшКонстант=СоздатьОбъект("СписокЗначений"); Соответственно вместо КтоТут=Константа.Дефчонки; пишем КтоТут=глКонстанта("Дефчонки"); |
|||
48
Ёпрст
21.05.13
✎
18:02
|
||||
49
lg2marvel
21.05.13
✎
18:21
|
Спасибо, буду ковырять
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |