Форум » LetoDB, HbNetio. » А работает ли механизм транзакций letodb » Ответить

А работает ли механизм транзакций letodb

PSP: в udf-функциях?

Ответов - 44, стр: 1 2 3 All

Pasha: Увы, нет. Механизм транзакции таков: все изменения накапливаются на клиенте без передачи на сервер, и только по LETO_COMMITTRANSACTION пакетом передаются на сервер, где и выполняются. Поскольку вызовы leto_udf сразу передаются на сервер и сразу выполняются, вписать их в механизм транзакций не представляется возможным.

PSP: Жаль. Подумалось, что было бы неплохо использовать свойство транзакции "либо выполняется целиком, либо не выполняется вообще" при записи из udf-функции, но, видимо, там уже напрямую работает rdd и "влезть" в этот процесс без переделки rdd не получится. Спасибо.

nbatocanin: Команда Leto_BeginTransaction() работает, только если DBF открыт с LetoDB. Например, это не работает: USE Test VIA "DBFNTX" NEW Leto_BeginTransaction() // Syntax error Почему? Это очень неудобно для универсальной процедурой которая копирует записи из локального DBF на сервер.


sashaBG: С транзакциями надо соблюдать следующие правила : 1. Использовать их только в зонах действия RDD "LETO" , другими словами после RDDSETDEFAULT( "LETO" ) а потом для взаимодействия между файлми разных RDD использовать алиасное имя 2. До закрытия транзакции нельзя использовать команду COMMIT. ( получится Sintax error) Может Паша посоветует еще чего то .

Pasha: Надо просто вызывать Leto_BeginTransaction() с рабочей областью, открытой через leto Пример: letotab->( Leto_BeginTransaction() )

nbatocanin: Я знаю, что это может решить проблему, но мне интересно, почему Leto_BeginTransaction() использует открытый DBF? Объяснение: в программе у меня есть следующие части: SELECT Tmp TransBegin() WHILE !Eof() TransProc() LetoTab->(DBAppend()) LetoTab->f1 := f1 LetoTab->f2 := f2 ... SKIP END DO TransEnd() Универсальные функции (TransBegin, TransProc и TransEnd) хочу, чтобы использовать во всей программы. Функция TransBegin на основе записи TMP (DBFNTX) устанавливает параметры и призывает Leto_BeginTransaction. Но TransBegin "не знает" за LetoTab, поэтому я вынужден передать и этот параметр. Вот почему я хочу знать, если он играет роль в Leto_BeginTransaction?

Pasha: Такое поведение связано с тем, что функции Leto_BeginTransaction необходимо знать, для какого соединения (сервера) letodb будет транзакция. Соединений же может быть несколько. Вот это соединение и берется из текущей рабочей области. А если эта р/о не leto, то генерируется ошибка.

nbatocanin: Спасибо! Я буду использовать любую открытую DBF. (Это не имеет большое значения, но я думаю, что это должно быть изменено).

nbatocanin: Когда я начал использовать транзакции, моя программа начала работать гораздо медленнее. Так что я сделал некоторые тесты. Тестовая программа копирует локальный DBF в таблице на сервере. Я обнаружил, что моя программа работает намного медленнее, чем Андреев DbfToServer. Например, таблицы 30000 записей: DbfToServer: 11 с моя программа: 65 с Чтобы скопировать, используя тот же алгоритм. После многих испытаний, я нашел разницу: моя DBF таблицы на сервере имеет индекс. Когда индекс выключен, программа значительно ускоряется. Это нормально, LetoDB требуется больше времени, чтобы обновить индекс. Но когда выключается транзакции, программа становится в несколько раз быстрее: 19 с! Почему? Это не логично. Тогда я попытался изменить размер буфера для транзакции. Я обменял буфер от 1000 до 50.0000, но я не заметил существенной разницы в скорости. Лучшие результаты имеют для буфера 3000-4000. DbfToServer определять размер буфера 1000 x RecordSize, но использует только 70%. Например, если размера данных 1500, тогда буфер 1.500.000, что я думаю, это слишком много. Что бы вы посоветовали?

nbatocanin: Продолжаю тестирования с индексами. Я сделал программу, которая копирует Test0 DBF (10000 записей) с локального диска на сервер в DBF Test2. Копирование выполняется следующим образом: 1. Тест2 не имеет индексов, без транзакции (-) 2. Тест2 имеет индексы, без транзакции (I) 3. Тест2 не имеет индексы, транзакции включены (T) 4. Тест2 имеет индексы, транзакции включены (I+T) Программа и результаты можно найти здесь: https://drive.google.com/folderview?id=0BwEGIJ1QfjrKY1NNLWRheENyUkE&usp=sharing Результаты показывают, что программа действительно замедляет, когда включены транзакции и индексы: [pre] Records - I T I+T ------------------------------- 90000 2.3 3.7 1.5 2.6 170000 2.2 2.3 1.5 3.0 730000 2.2 2.2 1.6 7.6 1450000 2.2 2.3 2.1 11.0 2010000 2.2 2.4 2.0 12.3 2050000 2.2 2.5 2.0 14.3[/pre] Почему это происходит? Результаты показывают, что операции и индексы не является проблемой, когда они не используются вместе.

Pasha: А в letodb.ini на сервере случайно нет строки: Share_Tables = 1 ?

nbatocanin: Да. Но я проверил вариант Share_Tables = 0 и получил аналогичные результаты: [pre2]Records - Ind Tran Ind+T ------------------------------- 2090000 2.3 10.2 1.5 14.5 2130000 2.1 2.4 1.8 14.6 2170000 2.2 2.3 1.8 14.4 2210000 2.5 2.4 1.9 15.3 2250000 2.3 2.2 2.0 14.8 2290000 2.5 2.7 2.1 15.8 2330000 2.4 2.5 2.0 14.9[/pre2]

Pasha: Что-то у меня не получается такой результат. А в prg по ссылке нет вообще операций с транзакциями. Я сделал свой тест с индексом: PROC Main Local cPath, nSec, i, nn := 0 Local lTr := .t. request leto, DBFCDX RddSetDefault ("LETO") cPath := "//127.0.0.1:2812/" Leto_Connect (cPath) USE (cPath + "wopl") SHARED NEW SET INDEX TO (cPath + "wopl") use wop new via "DBFCDX" go top nSec := Seconds() if lTr wopl->(leto_BeginTransaction(32768)) endif while ! eof() wopl->(dbAppend()) for i := 1 to fcount() wopl->(FieldPut(i, wop->(FieldGet(i)))) next if nn % 10000 == 0 .and. lTr wopl->(leto_CommitTransaction()) wopl->(leto_BeginTransaction(32768)) endif if ++nn == 100000 exit endif skip enddo if lTr wopl->(leto_CommitTransaction()) endif ? Seconds() - nSec // 23.87 -T+I // 7.32 +T+I RETURN Результат работы для 100000 записей: 23.87 сек без транзакций 7.32 сек с транзакциями Т.е. передача файла, если использовать транзакции, выполняется примерно в 3 раза быстрее. Одну большую транзакцию я разбил на небольшие по 10000 записей. Может быть, выложите свой тест, в котором получается медленный результат при использовании транзакций ?

nbatocanin: DBF Wop (локальный) не должен быть больше, чем 10.000 записей. Основная проблема находится в WopL (на сервере). DBF на сервере должен иметь более 500.000 записей и минимум два индекса. Когда есть меньше записей или индекс, скорость увеличивается. Я пробовал ваш тест программ (Wop = 10k записей): [pre2]WopL Index -T+I +T+I -------------------------------------- 10k 1 4.2 3.9 10k 2 4.2 4.5 2M 1 4.4 7.4 2M 2 4.3 13.0 [/pre2]

Pasha: Большие dbf можно взять здесь: http://www.gnivc.ru/html/gnivcsoft/KLADR/Base.7z Я взял doma.dbf, более 2-х млн.записей, размер более 200MB Создал много (9) индексов: имя тэга ключ code 'CODE' namec 'SUBSTR(CODE,1,11)+UPPER(NAME)' nasel 'SUBSTR(CODE,1,11)' nameg 'SUBSTR(CODE,1,8)+UPPER(NAME)' namemp 'SUBSTR(CODE,1,5)+UPPER(NAME)' ocato 'OCATD' gni 'GNINMB' scode 'SUBSTR(CODE,1,2)' s_code 'SUBSTR(CODE,1,15)' Прогнал по сети тест с копированием 100000 записей на сервер letodb без транзакций, и с транзакциями по 10000 записей Результат теста: Без транзакций: 154 сек С транзакциями: 44 сек Вот чуть измененный тест: PROC Main Local cPath, nSec, i, nn := 0 Local cNm := 'doma' Local lTr := .t. request leto, DBFCDX RddSetDefault ("LETO") cPath := "//10.0.0.1:2812/" //cPath := "//127.0.0.1:2812/" Leto_Connect (cPath) USE (cPath + cNm) alias db_srv SHARED NEW SET INDEX TO (cPath + cNm) use (cNm) alias db_loc new via "DBFCDX" go top nSec := Seconds() if lTr db_srv->(leto_BeginTransaction(32768)) endif while ! eof() db_srv->(dbAppend()) for i := 1 to fcount() db_srv->(FieldPut(i, db_loc->(FieldGet(i)))) next if nn % 10000 == 0 ? nn if lTr db_srv->(leto_CommitTransaction()) db_srv->(leto_BeginTransaction(32768)) endif endif if ++nn == 100000 exit endif skip enddo if lTr db_srv->(leto_CommitTransaction()) endif ? lTr, Seconds() - nSec RETURN

nbatocanin: Я использую NTX индексы, предполагают, что это может быть проблема. Программа с CDX индексов работать быстрее - время сокращается с 13 до 4,4 секунд. Вы можете проверить это? К сожалению, я должен использовать NTX индексов.

Pasha: Ну никак не получается у меня эффект медленной транзакции. Для ntx копирование 15000 записей с 9 индексами: без транзакции примерно 7 сек, с транзакциями - 6 сек. letodb.ini: DataPath = e:/db EnableFileFunc = 1 EnableAnyExt = 1 Optimize = 1 AutOrder = 1 Default_Driver = NTX тест: PROC Main Local cPath, nSec, i, nn := 0 Local cNm := 'doma' Local lTr := .t. Field Code, OCATD, GNINMB request leto, DBFCDX RddSetDefault ("LETO") //cPath := "//10.0.0.1:2812/" cPath := "//127.0.0.1:2812/" Leto_Connect (cPath) USE (cPath + cNm) alias db_srv SHARED NEW if ! leto_File(cPath+cNm+'.ntx') ? 'Indexing...' index on CODE to doma1 index on SUBSTR(CODE,1,11) to doma2 index on SUBSTR(CODE,1,11) to doma3 index on SUBSTR(CODE,1,8) to doma4 index on SUBSTR(CODE,1,5) to doma5 index on OCATD to doma6 index on GNINMB to doma7 index on SUBSTR(CODE,1,2) to doma8 index on SUBSTR(CODE,1,15) to doma9 endif SET INDEX TO (cPath + cNm + '1') SET INDEX TO (cPath + cNm + '2') SET INDEX TO (cPath + cNm + '3') SET INDEX TO (cPath + cNm + '4') SET INDEX TO (cPath + cNm + '5') SET INDEX TO (cPath + cNm + '6') SET INDEX TO (cPath + cNm + '7') SET INDEX TO (cPath + cNm + '8') SET INDEX TO (cPath + cNm + '9') dbSetOrder(1) use (cNm) alias db_loc new via "DBFCDX" go top nSec := Seconds() if lTr db_srv->(leto_BeginTransaction(32768)) endif while ! eof() db_srv->(dbAppend()) for i := 1 to fcount() db_srv->(FieldPut(i, db_loc->(FieldGet(i)))) next if nn % 10000 == 0 ? nn if lTr db_srv->(leto_CommitTransaction()) db_srv->(leto_BeginTransaction(32768)) endif endif if ++nn == 15000 exit endif skip enddo if lTr db_srv->(leto_CommitTransaction()) endif ? lTr, Seconds() - nSec RETURN

nbatocanin: LetoDB.ini: Default_Driver = NTX EnableFileFunc = 1 Optimize = 1 сервер: Windows Server 2003, 100Mb LAN рабочая станция: Windows 7 SET INDEX TO (cPath + cNm + '1') SET INDEX TO (cPath + cNm + '2') SET INDEX TO (cPath + cNm + '3') SET INDEX TO (cPath + cNm + '4') SET INDEX TO (cPath + cNm + '5') SET INDEX TO (cPath + cNm + '6') SET INDEX TO (cPath + cNm + '7') SET INDEX TO (cPath + cNm + '8') SET INDEX TO (cPath + cNm + '9') dbSetOrder(1) Я думаю, что это только открывает последний индекс. Попробуйте: SET INDEX TO (cPath + cNm + '1'), (cPath + cNm + '2'), (cPath + cNm + '3'), ... Я попробую тест на другом сервере. Спасибо за помощь!

Pasha: Да, я почти сразу заметил, что пропустил ADDITIVE. Но и с этой опцией результат не изменился. Попробуйте мой тест с файлом по ссылке, что я дал. Может быть, в вашем тесте есть еще какие-нибудь особенности.

nbatocanin: результаты: без транзакций : 8.5 С транзакциями: 6.5 Это нормальный результат. Тогда я изменил DBF, добавил числовое поле ID (N10), заполнил ID = RecNo(). После этого изменил тестовую программу таким образом, чтобы она использует только два индекса: index on ID to doma1 index on Upper(NAME) to doma2 Потом я получил следующие результаты: без транзакции: 6.3 С транзакциями: 9.0 Когда я добавил третий числовой индекс: index on ID to doma3 получил: без транзакции: 6.4 С транзакциями: 11.2 Кажется, что проблема в числовых полях в индексе.



полная версия страницы