16.10.2008, 09:27 | #1 |
Участник
|
Есть ли какие-то тонкости работы с темп-таблицами в плане быстродействия?
У меня довольно простой код выполняется достаточно долго, как мне кажется. Вот такая вот у меня процедурка (привожу полностью как есть, может кому что бросится в глаза): UpdateAvailableCapacity(VAR CurrCapacityRec : TEMPORARY Record "Availability Buffer") CurrCapacityRec."Available Quantity":= (CurrCapacityRec."Ending Date"-CurrCapacityRec."Starting Date")*24 +(CurrCapacityRec."Ending Time"-CurrCapacityRec."Starting Time")/3600000; LocBegin:=CREATEDATETIME(CurrCapacityRec."Starting Date",CurrCapacityRec."Starting Time"); LocEnd:=CREATEDATETIME(CurrCapacityRec."Ending Date",CurrCapacityRec."Ending Time"); TmpTimeBreakeCapacity.RESET; TmpTimeBreakeCapacity.SETCURRENTKEY("Starting Date","Starting Time","Ending Date","Ending Time"); TmpTimeBreakeCapacity.SETFILTER("Starting Date",'<=%1',CurrCapacityRec."Ending Date"); TmpTimeBreakeCapacity.SETFILTER("Ending Date",'>=%1',CurrCapacityRec."Starting Date"); TmpTimeBreakeCapacity.SETRANGE("Line No.",CurrCapacityRec."Entry No."); IF TmpTimeBreakeCapacity.FIND('-') THEN REPEAT BreakBegin:=CREATEDATETIME(TmpTimeBreakeCapacity."Starting Date",TmpTimeBreakeCapacity."Starting Time"); BreakEnd:=CREATEDATETIME(TmpTimeBreakeCapacity."Ending Date",TmpTimeBreakeCapacity."Ending Time"); IF (BreakBegin<=LocBegin) AND (BreakEnd>=LocEnd) THEN BEGIN CurrCapacityRec."Available Quantity":=0; EXIT; END ELSE IF (BreakBegin<=LocBegin) AND (BreakEnd<=LocEnd) AND (BreakEnd>LocBegin) THEN CurrCapacityRec."Available Quantity":=CurrCapacityRec."Available Quantity"-(BreakEnd-LocBegin)/3600000 ELSE IF (BreakBegin>LocBegin) AND (BreakEnd<=LocEnd) THEN CurrCapacityRec."Available Quantity":=CurrCapacityRec."Available Quantity"-TmpTimeBreakeCapacity."Available Quantity" ELSE IF (BreakBegin>LocBegin) AND (BreakBegin<LocEnd) AND (BreakEnd>=LocEnd) THEN CurrCapacityRec."Available Quantity":=CurrCapacityRec."Available Quantity"-(LocEnd-BreakBegin)/3600000; UNTIL TmpTimeBreakeCapacity.NEXT=0; CurrCapacityRec и TmpTimeBreakeCapacity являются темп-таблицами. Работает такая процедура примерно 0,036 секунды. Цикл по TmpTimeBreakeCapacity проходит около 3-6 записей. Комп вполне работоспособный (процессор Pentium 1,73 GHz, 795 МГц, 1Гб ОЗУ) |
|
16.10.2008, 09:55 | #2 |
Участник
|
Удивлен, что пост от девочки (простите за "девочку" уважаемая, но у меня все, кто не мальчик - девочки).
Это из-за конструктива. По теме - ну не знаю, почему код выполняется настолько долго. Не по теме. Более читабельно в коде смотрится конструкция CASE нежели IF .. ELSE IF .. ELSE IF. Поясню. Код: CASE TRUE OF (BreakBegin<=LocBegin) AND (BreakEnd>=LocEnd) : BEGIN ... END; (BreakBegin<=LocBegin) AND (BreakEnd<=LocEnd) AND (BreakEnd>LocBegin) : BEGIN ... END; END; |
|
16.10.2008, 10:00 | #3 |
Участник
|
Цитата:
Сообщение от romeo
Удивлен, что пост от девочки (простите за "девочку" уважаемая, но у меня все, кто не мальчик - девочки).
Это из-за конструктива. По теме - ну не знаю, почему код выполняется настолько долго. Не по теме. Более читабельно в коде смотрится конструкция CASE нежели IF .. ELSE IF .. ELSE IF. Поясню. Код: CASE TRUE OF (BreakBegin<=LocBegin) AND (BreakEnd>=LocEnd) : BEGIN ... END; (BreakBegin<=LocBegin) AND (BreakEnd<=LocEnd) AND (BreakEnd>LocBegin) : BEGIN ... END; END; To All. Простите меня за два поста. Я кнопку не ту нажал. Это как в анеке про блондинку - печатаю быстро, но иногда такая фигня получается -) |
|
16.10.2008, 10:50 | #4 |
Участник
|
На счет конструкции Case - да, действительно читабильнее. Это у меня исторически сложилось, IF-ами писать, уж и не знаю почему.
По поводу критического значения в 10000 записей - спасибо, такая инфа тоже пригодится, но в данном случае кол-во записей на порядки меньше. P.S. Забавно, что девушки-программисты все еще кого-то удивляют |
|
16.10.2008, 11:35 | #5 |
Участник
|
Цитата:
Сообщение от Nataly
Код: TmpTimeBreakeCapacity.RESET; TmpTimeBreakeCapacity.SETCURRENTKEY("Starting Date","Starting Time","Ending Date","Ending Time"); TmpTimeBreakeCapacity.SETFILTER("Starting Date",'<=%1',CurrCapacityRec."Ending Date"); TmpTimeBreakeCapacity.SETFILTER("Ending Date",'>=%1',CurrCapacityRec."Starting Date"); TmpTimeBreakeCapacity.SETRANGE("Line No.",CurrCapacityRec."Entry No."); IF TmpTimeBreakeCapacity.FIND('-') THEN |
|
16.10.2008, 14:41 | #6 |
Участник
|
Вообще я полагала, что при работе с темповскими таблицами действуют другие правила и выбор ключа не влияет на производительность. Но вот сейчас попробовала заменить ключ и время сократилось в 2 раза! Одного запуска конечно мало для выводов, сейчас еще буду тестить, но в любом случае спасибо!
|
|
16.10.2008, 15:53 | #7 |
Участник
|
|
|
16.10.2008, 21:31 | #8 |
Участник
|
1. CASE, мо-моему, не только читабельнее, но и чуть-чуть быстрее чем IF..ELSE..IF
2. SETRANGE, по-моему, тоже быстрее чем SETFILTER, поэтому конкретно в этом случае можно обе даты фильтровать не с SETFILTER Код: TmpTimeBreakeCapacity.SETFILTER("Starting Date",'<=%1',CurrCapacityRec."Ending Date"); TmpTimeBreakeCapacity.SETFILTER("Ending Date",'>=%1',CurrCapacityRec."Starting Date"); Код: TmpTimeBreakeCapacity.SETRANGE("Starting Date",0D,CurrCapacityRec."Ending Date"); TmpTimeBreakeCapacity.SETRANGE("Ending Date",CurrCapacityRec."Starting Date", 2999D); Если есть вероятность, что не всегда имеется отфильтрованная запись в TmpTimeBreakeCapacity, то можно перед FIND'ом это проверить через ISEMPTY, т.к. лишний (и не нашедший запись) FIND стоит по времени дороже: Код: .............. TmpTimeBreakeCapacity.SETRANGE("Starting Date",0D,CurrCapacityRec."Ending Date"); TmpTimeBreakeCapacity.SETRANGE("Ending Date",CurrCapacityRec."Starting Date", 2999D); TmpTimeBreakeCapacity.SETRANGE("Line No.",CurrCapacityRec."Entry No."); IF TmpTimeBreakeCapacity.ISEMPTY THEN EXIT ELSE TmpTimeBreakeCapacity.FINDFIRST; REPEAT ... UNTIL TmpTimeBreakeCapacity.NEXT = 0; |
|
16.10.2008, 22:20 | #9 |
Участник
|
3. Если позволяет версия Navision и база данных на SQL, то вместо FIND('-'), FIND('+') использоватъ FINDFIRST, FINDLAST
Если есть вероятность, что не всегда имеется отфильтрованная запись в TmpTimeBreakeCapacity, то можно перед FIND'ом это проверить через ISEMPTY, т.к. лишний (и не нашедший запись) FIND стоит по времени дороже: уважаемый AlexB в данном примере помоему Вы не правы. приведу выдержку хелпа по FINDFIRST Comment This function should be used instead of FIND('-') when you only need the first record. You should only use this function when you explicitly want to find the first record in a table/set. Do not use this function in combination with REPEAT .. UNTIL. |
|
17.10.2008, 08:17 | #10 |
Участник
|
Вообще пишу под 4.0 SP3, но возможно код будет использовано и под другими версиями (как ниже, так и выше). БД под SQL Server.
Цитата:
Сообщение от AlexB
1. CASE, мо-моему, не только читабельнее, но и чуть-чуть быстрее чем IF..ELSE..IF
2. SETRANGE, по-моему, тоже быстрее чем SETFILTER, поэтому конкретно в этом случае можно обе даты фильтровать не с SETFILTER Относительно FINDFIRST, FINDLAST и т.д. Не хотелось их использовать, чтобы безболезненно код переносить под другие версии. А вообще, разве все это имеет значение для темп-таблиц? Для реальных-то понятно, что быстрее, там запрос на сервер отправляется, а тут же локально все. Цитата:
Сообщение от anatol33
приведу выдержку хелпа по FINDFIRST
Comment This function should be used instead of FIND('-') when you only need the first record. You should only use this function when you explicitly want to find the first record in a table/set. Do not use this function in combination with REPEAT .. UNTIL. Кстати, я основательно затестила, использование наиболее подходящих ключей очень помогло, скорость существенно улучшилась, спасибо! |
|
17.10.2008, 10:10 | #11 |
Участник
|
За FINDFIRST/FINDLAST извиняюсь, в REPEAT..UNTIL надо конечно использовать FINDSET.
Т.к. код выполняется в различных NAV-версиях, то и в данном конкретном случае FIND('-') придётся оставить. Кстати, может не совсем в тему топика: почему и в новых версиях NAV'а (5.0 SP1) в коде стандарта ещё во многих местах в REPEAT..UNTIL используется FIND('-')? |
|
17.10.2008, 11:05 | #12 |
Участник
|
Цитата:
P.S. Кстати, можете глянуть в Clent Monitor что твориться под SQL |
|
17.10.2008, 14:37 | #13 |
Участник
|
Цитата:
Сообщение от anatol33
приведу выдержку хелпа по FINDFIRST
Comment This function should be used instead of FIND('-') when you only need the first record. You should only use this function when you explicitly want to find the first record in a table/set. Do not use this function in combination with REPEAT .. UNTIL. |
|
20.10.2008, 08:48 | #14 |
Участник
|
Цитата:
По крайней мере Clent Monitor видит только запросы к базе, работу с темп-таблицами он не отражает. |
|
06.11.2008, 16:25 | #15 |
Участник
|
Цитата:
Далее все эти таблицы хранятся в памяти и если её не достаточно, то будет происходить сброс на винт и восстановление. А так как куча фильтров ставится, то я не уверен, что всё хранится в памяти! |
|
06.11.2008, 17:39 | #16 |
Участник
|
Цитата:
Сообщение от RedFox
"Работает такая процедура примерно 0,036 секунды. " - Это с с заполнением этой временной таблицы в памяти или ТОЛЬКО сравнение?
Далее все эти таблицы хранятся в памяти и если её не достаточно, то будет происходить сброс на винт и восстановление. А так как куча фильтров ставится, то я не уверен, что всё хранится в памяти! По теме: Есть видимо некий порог, когда производительнее использовать возможности SQL сервера, нежели работать с черным ящиком, именуемым временные таблицы. Предполагаю используется тот же самый механизм что и для работы с native DB. |
|
07.11.2008, 13:14 | #17 |
Участник
|
Цитата:
А вы хотите сказать, что торможение вызвано работой с винтиком, да? Это по крайней мере понятно будет. Цитата:
Сообщение от rmv
По теме: Есть видимо некий порог, когда производительнее использовать возможности SQL сервера,
нежели работать с черным ящиком, именуемым временные таблицы. Предполагаю используется тот же самый механизм что и для работы с native DB. |
|