Вопросы по FIBL

Модератор: Модераторы

Вопросы по FIBL

Сообщение alexber220_job » 10.12.2007 12:37:39

Задача скопировать данные из одной FB базы в идентичную другую FB базу.

Сначало хотел на UIB сделать, но там проблемы с копированием BLOB
http://www.progdigy.com/modules.php?nam ... pic&t=4050

Сейчас сделал на FIBL но при копировании BLOB полей память течёт очень жёстко.

Вариант на FIBL.

Код: Выделить всё
// открытие FB базы.
// @param DBHost сервер где установлена СУБД
// @param DBName имя базы (путь к файлу или алиас)
// @param UserName имя пользователя
// @param Password пароль
// @return ссылка на TFIBDatabase, к которому привязан TFIBTransaction
// @seealso FBDBClose
function FBDBOpen(DBHost, DBName, UserName, Password:string):pointer;
var
  FBDB: TFIBDatabase;
  FBDBT: TFIBTransaction;
  DBPath: String;
begin
  result := nil;
  DBPath := '';
  if (length(DBHost) > 0) then
     DBPath := DBHost + ':';
  DBPath := DBPath + DBName;

  FBDB := TFIBDatabase.Create(nil);
  result := FBDB;
  FBDB.DBName := DBPath;
  FBDB.UserName := UserName;
  FBDB.Password := Password;
  FBDB.Encoding := 'WIN1251';

  FBDBT := TFIBTransaction.Create(nil);
  FBDBT.TRParams.Add('read_committed');
  FBDBT.TRParams.Add('rec_version');
  FBDBT.TRParams.Add('nowait');
  FBDBT.DefaultDatabase := FBDB;
  FBDB.DefaultTransaction := FBDBT;

  try
    FBDB.Connected := True;
  except
    raise Exception.Create('Не удалось соединиться с FB базой');
  end;
end;// function FBDBOpen


// закрытие FB базы.
// @param DB открытая ранее база (ссылка на TFIBDatabase, к которому привязан
//        TFIBTransaction)
// @seealso FBDBOpen
procedure FBDBClose(DB:pointer);
begin
  if DB <> nil then
  begin
    TFIBDatabase(DB).Close;
    TFIBDatabase(DB).Free;
  end;
end;// procedure FBDBClose


function CopyTableFBToFB(FBDBFrom, FBDBTo:pointer;
         table, filter:AnsiString):boolean;
var
  FBFromDataSet, FBToDataSet : TFIBDataSet;
  FieldsSQL, ValuesSQL:string;
  request:AnsiString;
  i : integer;
  RecordsInTransaction : integer;
  blob_stream:TMemoryStream;
begin
  result := true;
  FieldsSQL := '';
  ValuesSQL := '';

  FBFromDataSet := TFIBDataSet.Create(nil);
  FBFromDataSet.Database := TFIBDatabase(FBDBFrom);
  FBFromDataSet.Transaction := TFIBDatabase(FBDBFrom).DefaultTransaction;
  FBFromDataSet.Transaction.StartTransaction;

  FBFromDataSet.SelectSQL.Clear;
  request := 'SELECT * FROM ' + table;
  if (length(filter) <> 0) then
     request := request + ' WHERE ' + filter;
  FBFromDataSet.SelectSQL.Add(request);
  FBFromDataSet.Open;

  FBToDataSet := TFIBDataSet.Create(nil);
  FBToDataSet.Database := TFIBDatabase(FBDBTo);
  FBToDataSet.Transaction := TFIBDatabase(FBDBTo).DefaultTransaction;
  FBToDataSet.Transaction.StartTransaction;
  FBToDataSet.SelectSQL.Clear;
  FBToDataSet.SelectSQL.Add('SELECT * FROM ' + table);

  // формирование запроса на вставку
  for i:= 0 to FBFromDataSet.FieldCount-1 do
  begin
    if AnsiCompareStr(AnsiLowerCase(FBFromDataSet.Fields.Fields[i].FieldName), 'type') = 0 then
      FieldsSQL := FieldsSQL + '"' + AnsiUpperCase(FBFromDataSet.Fields.Fields[i].FieldName) + '"'
    else
      FieldsSQL := FieldsSQL + FBFromDataSet.Fields.Fields[i].FieldName;

    if i < FBFromDataSet.FieldCount-1 then
      FieldsSQL := FieldsSQL + ','
  end;
  ValuesSQL := ':' + StringReplace(FieldsSQL, ',', ',:', [rfReplaceAll]);
  FBToDataSet.InsertSQL.Clear;
  FBToDataSet.InsertSQL.Add('INSERT INTO ' + table +
      '(' + FieldsSQL + ') VALUES (' + ValuesSQL + ')');
  FBToDataSet.Open;

  // проверка на соотвествие полей
  for i:= 0 to FBFromDataSet.FieldCount-1 do
    if (FBFromDataSet.Fields.Fields[i].FieldName <> FBToDataSet.Fields.Fields[i].FieldName) or
       (FBFromDataSet.Fields.Fields[i].DataType <> FBToDataSet.Fields.Fields[i].DataType)
    then
    begin
      result := false;
      break;
    end;

  // копирование
  RecordsInTransaction := 0;
  try
    FBFromDataSet.First;
    while not FBFromDataSet.Eof do
    begin
      FBToDataSet.Insert;
      for i:= 0 to FBFromDataSet.FieldCount-1 do
      begin
        if (FBToDataSet.Fields.Fields[i].DataType = ftBlob) then
        begin
          blob_stream := TMemoryStream.Create();
          TBlobField(FBFromDataSet.Fields.Fields[i]).SaveToStream(blob_stream);
          TBlobField(FBToDataSet.Fields.Fields[i]).LoadFromStream(blob_stream);
          blob_stream.Clear;
          blob_stream.Free;
        end
        else
          FBToDataSet.FieldByName(FBToDataSet.Fields.Fields[i].FieldName).Assign(
            FBFromDataSet.FieldByName(FBToDataSet.Fields.Fields[i].FieldName));
      end;
      FBToDataSet.Post;

      // ограничение на кол-во записей вставляемых в рамках одной транзакции
      inc(RecordsInTransaction);
      if RecordsInTransaction > MaxRecordsInTransaction then
        FBToDataSet.Transaction.CommitRetaining;

      FBFromDataSet.Next;
    end;// while not FBFromDataSet.Eof do
  except
    result := false;
  end;


  // освобождение ресурсов
  if result then
    FBToDataSet.Transaction.Commit
  else
    FBToDataSet.Transaction.Rollback;
  FBToDataSet.Close;
  FBToDataSet.Free;
  FBFromDataSet.Close;
  FBFromDataSet.Free;
end;// function CopyTableFBToFB



procedure TForm1.Button3Click(Sender: TObject);
var
  from_db, to_db:pointer;
begin
  from_db := FBDBOpen('', 'D:\AlexBer\MOD\MOD_TEST\MOD_TEST.GDB',
        'sysdba', 'masterkey');
  to_db := FBDBOpen('', 'D:\AlexBer\MOD\LazMod\DB_TEST.GDB',
        'sysdba', 'masterkey');
       
  CopyTableFBToFB(from_db, to_db, 'table1', '');

  FBDBClose(to_db);
  FBDBClose(from_db);
end;


в TFIBQuery не нашёл где кол-во полей брать.

что я сделал не так?
Последний раз редактировалось alexber220_job 11.12.2007 09:12:07, всего редактировалось 1 раз.
alexber220_job
незнакомец
 
Сообщения: 7
Зарегистрирован: 10.12.2007 12:29:56

Сообщение ev » 10.12.2007 19:52:35

что я сделал не так?

забыл поставить тег code ;)
ev
долгожитель
 
Сообщения: 1764
Зарегистрирован: 27.04.2005 23:19:06
Откуда: Москва

Сообщение alexs » 10.12.2007 20:36:20

alexber220_job
Приязнаюсь честно - я видел твой пост на UIB, но в таком большом куске кода - просто разбираться не хочется.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4053
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Сообщение alexber220_job » 11.12.2007 09:11:38

alexs писал(а):alexber220_job
Приязнаюсь честно - я видел твой пост на UIB, но в таком большом куске кода - просто разбираться не хочется.


суть в том что скопировал из примера
C:\lazarus\components\UIB\examples\JvUIB\Component\CloneDatabase\
и не работает :(
написано вроде читабельно не DataSet1 и DataSet2 а FBFromDataSet, FBToDataSet при желании за 5 минут разобраться можно.
а все его нахваливают.
неужто я один с блобами работаю?
очередной лисапед городить тоже не хочется
так что с утечкой памяти? она меня сейчас больше волнует
не ужто на линух не портировать столь важную прогу?
проще былоб на питоне написать :( неделю только на блобы убил сейчас ещё память течёт непонятно где. :(
alexber220_job
незнакомец
 
Сообщения: 7
Зарегистрирован: 10.12.2007 12:29:56

Сообщение alexber220_job » 11.12.2007 11:14:01

После TBlobField(FBFromDataSet.Fields.Fields[i]).SaveToStream(blob_stream);

добавил
TBlobField(FBFromDataSet.Fields.Fields[i]).Clear;

сейчас течёт меньше но течёт на 8000 записей с 15 мб программа толстеет до 60
alexber220_job
незнакомец
 
Сообщения: 7
Зарегистрирован: 10.12.2007 12:29:56

Сообщение tria » 11.12.2007 11:35:27

Попробуй поставь
blob_stream := TMemoryStream.Create();
до начала выборки
а
blob_stream.Free;
в конце, где идет "освобождение ресурсов"
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение alexber220_job » 11.12.2007 11:48:32

tria писал(а):Попробуй поставь
blob_stream := TMemoryStream.Create();
до начала выборки
а
blob_stream.Free;
в конце, где идет "освобождение ресурсов"


Это не помогает но чтоб нагрузку не создавать сделал.
сейчас проблемная строка это
TBlobField(FBToDataSet.Fields.Fields[i]).LoadFromStream(blob_stream);

после
FBToDataSet.Transaction.CommitRetaining;
добавил
FBToDataSet.Close;
FBToDataSet.Open;

сервер FB повесился после ~4,5 записей
alexber220_job
незнакомец
 
Сообщения: 7
Зарегистрирован: 10.12.2007 12:29:56

Сообщение alexber220_job » 11.12.2007 12:09:09

сделал пока так
Код: Выделить всё
      if RecordsInTransaction > MaxRecordsInTransaction then
      begin
        FBToDataSet.Transaction.CommitRetaining;
        FBToDataSet.Close;
        FBToDataSet.Open;
        RecordsInTransaction := 0;
      end;


топорно, тормозно но течёт ещё меньше
alexber220_job
незнакомец
 
Сообщения: 7
Зарегистрирован: 10.12.2007 12:29:56

Сообщение Сергей Смирнов » 11.12.2007 12:20:59

А CommitRetaining зачем? Почему не просто Commit?
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва

Сообщение alexber220_job » 12.12.2007 20:48:53

Сергей Смирнов писал(а):А CommitRetaining зачем? Почему не просто Commit?


Если менять не работает.
Но суть дела это не меняет. Течёт эта строка TBlobField(FBToDataSet.Fields.Fields[i]).LoadFromStream(blob_stream);
alexber220_job
незнакомец
 
Сообщения: 7
Зарегистрирован: 10.12.2007 12:29:56

Сообщение alexber220_job » 12.12.2007 21:52:52

удалось уменьшить утечку за счёт добавления
после
FBToDataSet.Post;

добавил
for i:= 0 to FBFromDataSet.FieldCount-1 do
begin
if (FBToDataSet.Fields.Fields[i].DataType = ftBlob) then
TBlobField(FBToDataSet.Fields.Fields[i]).Clear;
end;

после перелива 40тыс записей 60Мб надеюсь хватит.
всем спасибо.
alexber220_job
незнакомец
 
Сообщения: 7
Зарегистрирован: 10.12.2007 12:29:56


Вернуться в Базы данных

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru