Перекачивание данных

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
ILI4
Сообщения: 21
Зарегистрирован: 07 сен 2006, 15:21

Перекачивание данных

Сообщение ILI4 » 09 фев 2007, 15:35

Здравствуйте!
Решил я написать для себя процедурку, которая перекачивала одинаковые по структуре таблицы из одной базы в другую. Знаю, что дело это неблагородное, и IBPump мне не переплюнуть, но нужна она мне, чтобы пользователь одну кнопочку нажал и все. Процедуру я оформил следующим образом в C++Builder:

Код: Выделить всё

void CopyIBTable(TIBDatabase *SourceDB,TIBDatabase *DestDB,String SourceTable,String DestTable,bool clear_dest)
{
  Screen->Cursor=crHourGlass;
    TIBTransaction *Read_Transaction=new TIBTransaction(Application);
  TIBTransaction *Write_Transaction=new TIBTransaction(Application);

  Read_Transaction->DefaultDatabase=SourceDB;
  Write_Transaction->DefaultDatabase=DestDB;

  Read_Transaction->Active=false;
  Write_Transaction->Active=false;

  SourceDB->AddTransaction(Read_Transaction);
  DestDB->AddTransaction(Write_Transaction);

  Read_Transaction->Params->Clear();
  Read_Transaction->Params->Add("read");
  Read_Transaction->Params->Add("read_committed");
  Read_Transaction->Params->Add("rec_version");
  Read_Transaction->Params->Add("nowait");

  Write_Transaction->Params->Clear();
  Write_Transaction->Params->Add("write");
  Write_Transaction->Params->Add("concurrency");
  Write_Transaction->Params->Add("nowait");

  TIBQuery *RQuery=new TIBQuery(Application);
  RQuery->Database=SourceDB;
  RQuery->Transaction=Read_Transaction;

  TIBQuery *WQuery=new TIBQuery(Application);
  WQuery->Database=DestDB;
  WQuery->Transaction=Write_Transaction;
  
  if (clear_dest)
   {
      Write_Transaction->StartTransaction();
      WQuery->Active=false;
      WQuery->SQL->Text="DELETE FROM "+DestTable;
      WQuery->ExecSQL();
      Write_Transaction->Commit();
   }

  RQuery->Active=false;
  RQuery->SQL->Text="SELECT * FROM "+SourceTable;
  RQuery->Open();


  String InsertSQL="INSERT INTO "+DestTable+(String)" (";
  String FieldNames="",ParamsNames="";

  for (int i=0;i<RQuery->FieldCount;i++)
   {
    FieldNames+=RQuery->Fields->Fields[i]->FieldName+",";
    ParamsNames+=":"+RQuery->Fields->Fields[i]->FieldName+",";
   }

  FieldNames.Delete(FieldNames.Length(),1);
  ParamsNames.Delete(ParamsNames.Length(),1);

  InsertSQL+=FieldNames+") values ("+ParamsNames+")";
  int counter=0;

  Write_Transaction->StartTransaction();
  WQuery->Active=false;
  WQuery->SQL->Text=InsertSQL;

  RQuery->First();
 
 while (!RQuery->Eof)
    {
       for (int i=0;i<RQuery->FieldCount;i++)
        {
          WQuery->Params->Items[i]->AssignFieldValue(RQuery->Fields->Fields[i],RQuery->Fields->Fields[i]->OldValue);
        }
    WQuery->ExecSQL();
    counter++;
    RQuery->Next();

    if (counter%1000==0)
     {
     Write_Transaction->Commit();
     Write_Transaction->StartTransaction();
     }
   
 }


  RQuery->Active=false;
  WQuery->Active=false;
  Write_Transaction->Active=false;
  Read_Transaction->Active=false;
  SourceDB->RemoveTransactions();
  DestDB->RemoveTransactions();
  delete RQuery;RQuery=NULL;
  delete WQuery;WQuery=NULL;
  delete Write_Transaction;Write_Transaction=NULL;
  delete Read_Transaction;Read_Transaction=NULL;
  Screen->Cursor=crDefault;
  }
Заранее я предполагаю, что таблица - приемник не проиндексирована.
Решил попробовать данную процедуру на таблице, в которой 70000 тысяч записей и около тридцати полей. Проц у меня Celeron 2.2, оперативки 256, Firebird 1.5.3. Не густо, но думаю что такая задача для него особых трудностей вызывать не должна. В общем, 13 тысяч записей он за 10 минут с горем пополам перекачал (еле снял задачу, система повисла почти наглухо), почуял что что -то не так. Подскажите мне пожалуйста, что?
Конечно, скорее всего я изобретаю велосипед, я думаю что есть уже готовые процедуры, или методы решения, но что - то ничего не нашел. Может быть плохо искал...

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 09 фев 2007, 16:01

Блин, ну почему все сразу лезут на форум, не дочитав основной сайт?!?
А ну, бегом читать http://www.ibase.ru/devinfo/impexp.htm!

ILI4
Сообщения: 21
Зарегистрирован: 07 сен 2006, 15:21

Сообщение ILI4 » 09 фев 2007, 16:05

И еще. Сейчас погонял код в отладчике, заметил что тормоза начинаются после 10000 записей. На каждой 999 записи (т.е. 10999, 11999 и т.д.)

Код: Выделить всё

WQuery->ExecSQL();
выполняется очень долго(порядка 10-30 секунд), хотя в других случаях проскакивает моментально. Чем это может быть вызвано???

ILI4
Сообщения: 21
Зарегистрирован: 07 сен 2006, 15:21

Сообщение ILI4 » 09 фев 2007, 17:42

Спасибо! Летает!

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 09 фев 2007, 18:18

Спасибо! Летает!
значит, дочитал. Но.

НИКОГДА НЕ ИСПОЛЬЗУЙ Transaction.Active:=False !!!
Потому что в этом случае она завершится тем, что у нее прописано в DefaultAction.
Правильно писать в коде
StartTransaction
и Commit или Rollback

то же самое в отношении Query и всего прочего. Т.е. на 90% управление свойством Active - зло.

Ответить