Использование Logout/Commit

VAB> Здравствуйте, Олег.
VAB> Ответ на Ваше письмо от 22 сентября 2002 г., 22:38:50
VAB> Большое спасибо за Ваши ответ и мнение.
VAB> И если можно, один маленький вопрос.
VAB> Ранее Андрей Мялин мне уже советовал, правда для драйвера Pervasive
VAB> Btrieve, использовать пару LOGOUT()-COMMIT.
VAB> Теперь Вы советуете эту же пару для драйвера TPS.
VAB> Вопрос вот какой:
VAB> Каким образом применение транзакции влияет НА БУФЕРИЗАЦИЮ данных ?
VAB> Сознаюсь, что я ещс не пробовал этот метод для TPS, но обязательно
VAB> попробую.
VAB> И ещс один вопросик:
VAB> Ваши рекомендации по использованию пары STREAM()-FLUSH() относятся к
VAB> использованию пары LOGOUT()-COMMIT ?
VAB> Вы сами понимаете, что открытие-закрытие транзакции для каждого цикла
VAB> несколько замедлит обработку. Это я уже проходил и не один раз.
VAB> Или одну пару LOGOUT()-COMMIT применять для всех циклов обработки ?

Для драйвера «TopSpeed» (.TPS) транзакция, в отличии от драйвера «Clarion» (.DAT), не замедляет а УСКОРЯЕТ процесс обработки! И значительно! Раньше я как-то уже приводил сравнительные данные. В среднем, транзакция для TPS ускоряет процесс обработки (ADD/PUT/DELETE) ~5-10 раз. Бывает меньше, но бывает и больше!

Это связано с тем, что после включения режима транзакции (оператором LOGOUT) ВСЕ изменения файлов, включенных в рамки текущей транзакции, накапливаются в оперативной памяти рабочей станции, на которой включена эта транзакция. Естественно, что при включении транзакции файлы автоматически блокируются от изменений на других станциях.
Т.е., во время транзакции файлы физически НЕ модифицируются. После отмены транзакции (оператором ROLLBACK) происходит простое очищение памяти рабочей станции и разблокирование файлов. После успешного завершения транзакции (оператором COMMIT) производится реальная модификация файлов в пакетном режиме, что ЗНАЧИТЕЛЬНО быстрее, чем пооператорная модификация.

В связи с вышесказанным, можно сделать вывод, что рамки одной транзакции ограничены двумя параметрами:

  • доступной оперативной памятью рабочей станции Что-бы не допустить свопинга, что значительно замедляет процесс и фактически сводит «на нет» все преимущество.
  • временем, которое необходимо для пакетной моификации рабочих файлов после успешного закрытия транзакции Иногда может достигать до 20-40 минут(!), что «нервирует» пользователя (так-как этот процесс не поддается никакой визуализации — ощущение что машина просто «висит») и может привести к порче файлов БД с потерей части данных при воникновении в это время нештатных ситуаций (сбой сетевой карточки или кабеля, вырубание электроэнергии и пр.).

Поэтому я и рекомендую не «заворачивать» большие циклы в один фрагмент LOGOUT-COMMIT. Что-то типа:

MaxCounter EQUATE(1000)
LOC:TranBreak BYTE
LOC:Logout BYTE
LOC:Counter LONG

...
do OpenTran
LOC:TranBreak = False
Clear(LOC:Counter)
Set(File)
Loop
Next(File); if ErrorCode() then Break.
! Модификация файла "File"
if ErrorCode()
LOC:TranBreak = True
Break
.
LOC:Counter += 1
do ReTran
.
do CloseTran
...

OpenTran Routine
Logout(1,File)
if ~ErrorCode() then LOC:Logout = True else LOC:Logout = False.

CloseTran Routine
if LOC:Logout
if LOC:TranBreak then RollBack() else Commit().
LOC:Logout = False
.

ReTran Routine
if (LOC:Counter % MaxCounter) = 0
do CloseTran
do OpenTran
.

В этом примере транзакционных буфер будет обновлятся каждые 1000 записей. Реальное значение константы MaxCounter лучше всего подбирать для каждой транзакции отдельно. В первую очередь оно зависит от общего размера буферов файлов, которые участвуют в рамках одной транзакции. Кол-во записей в этих файлах реально начинает влиять на это значение только при довольно больших кол-вах.

Да! И, естественно, в рамках транзакции нет надобности в использовании STREAM/FLUSH.