Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2007.04.08;
Скачать: [xml.tar.bz2];

Вниз

Обмен большими данными между Oracle и FireBird   Найти похожие ветки 

 
ildarkh   (2007-01-18 15:51) [0]

Существует такая проблема. Есть БД Oracle с таблицей на 500 тыс. записей. Нужно их все перегнать в соответствующую таблицу FireBird. Используется DBExpress.
Я написал с этой целью программу, поначалу крепко зависавшую из-за объема данных(в том числе на сервере с 3ггц Xeon и 4гб памяти). В случае сервера потребление памяти программой выростало до 500 мегабайт. Однако на меньших объемах данных программа работала исправно.
Я изменил код, который отвечает за запрос к Oracle. Но я что-то сделал неправильно. Программа продолжает жрать память и затем зависать. Код ниже, благодарю заранее

procedure TSelectInserts.SelInsExec(selins: IXMLSelectInsertType);
var i: integer;
repwith: string;
errstr: string;
TD: TTransactionDesc;
begin
try
Application.ProcessMessages;
TD.TransactionID := 1;
TD.IsolationLevel := xilREADCOMMITTED;
db2.StartTransaction(TD);
errstr := selins.Select.Query;
self.SelInsWork := 1;

db1.SQLClientDataSet.PacketRecords := 10000;
db1.SQLClientDataSet.FetchOnDemand := false;

db1.SelectQuery(selins.Select.Query, selins.Select.Params);
self.SelInsWork := 2;
i:=0;
while not db1.SQLClientDataSet.Eof do
 begin
 //db1.SQLClientDataSet.First;
 if db1.SQLClientDataSet.RecordCount > 0 then
 //for i:=1 to db1.SQLClientDataSet.RecordCount do
 while not db1.SQLClientDataSet.Eof do
   begin
   inc(i);
   self.InsProgressNum := i;
   errstr := selins.Insert.Query;
   if (i >= 1000 )and (i mod 1000 = 0) then
     begin
     db2.Commit(TD);
     db2.StartTransaction(TD);
     end;
   db2.UpdateQuery(selins.Insert.Query, selins.Fields, db1.DataSource.DataSet.Fields);
   db1.SQLClientDataSet.Next;
   Application.ProcessMessages;
   end;
 if db1.SQLClientDataSet.RecordCount > 0 then
 for i:=0 to selins.Select.Params.Count-1 do
   begin
   repwith := selins.Select.Params.Param[i].Replacewith;
   if(repwith <> "") then
      selins.Select.Params.Param[i].Text := db1.DataSource.DataSet.Fields.FieldByName(repwith).AsString;
 end;
 db1.SQLClientDataSet.GetNextPacket;
 end;
db2.Commit(TD);
xmldoc.SaveToFile(ExtractFilePath(ParamStr(0)) + "XML.xml");
except on e: Exception do
 begin
 db2.Rollback(TD);
 Logger.Write(3, e.Message + ": " + errstr);
 end;
end;
self.SelInsWork := 0;
end;


 
Johnmen   (2007-01-18 16:04) [1]

while not db1.SQLClientDataSet.Eof do
begin

//db1.SQLClientDataSet.First;
if db1.SQLClientDataSet.RecordCount > 0 then
//for i:=1 to db1.SQLClientDataSet.RecordCount do
while not db1.SQLClientDataSet.Eof do
  begin


Это так надо ? :)))


 
Desdechado ©   (2007-01-18 16:14) [2]

Зачем тебе CDS? Он кэширует данные на клиенте.
Тебе же, как я понял, надо построчно читать и тут же записывать.
Вот так и делай. Достаточно SQLDataSet использовать.


 
ildarkh   (2007-01-18 16:19) [3]

Во внешнем цикле проход осуществляется
db1.SQLClientDataSet.GetNextPacket;
Во внутреннем
db1.SQLClientDataSet.Next;

А признак db1.SQLClientDataSet.Eof вроде бы подходит для обоих случаев. Если я не прав, то скажите, в чем?


 
Johnmen ©   (2007-01-18 16:31) [4]

Ты непрв во всём.
Как сказал Desdechado, читаешь записи из входного набора данных, и тут же их пишешь (INSERT INTO). По одной.
Использовать лучше TSQLQuery.


 
ildarkh   (2007-01-18 16:33) [5]

Спасибо, я попробую.


 
ildarkh   (2007-01-18 16:36) [6]

Зачем вообще нужна передача пакетами в TSQLClientDataSet? Я читал, что с помощью них можно поэтапно откачивать данные с сервера БД.


 
Johnmen ©   (2007-01-18 16:42) [7]


> Зачем вообще нужна передача пакетами в TSQLClientDataSet?


Ну, видимо, быстрее пакетами. Хотя, я думаю, это "быстрее" никто не видел :)


 
Desdechado ©   (2007-01-18 17:15) [8]

Про ClientDataSet забудь. Он здесь не нужен в принципе. Достаточно однонаправленного SQLDataSet.

> Зачем вообще нужна передача пакетами в TSQLClientDataSet?
Во-первых, не передача, а прием в CDS.
Во-вторых, это сделано для того, чтобы в случае больших выборок на клиента не замораживать интерфейс вычиткой всей выборки сразу. Может, пользователю будет достаточно поглядеть на первых несколько пакетов, а еще 200 тыс записей ему и не нужны будут. А без пакетирования CDS их сначала все вытянет на клиента (если памяти хватит), а потом разморозит интерфейс.

> Я читал, что с помощью них можно поэтапно откачивать данные с сервера БД.
Правильно. Но только не длятвоего случая. Поскольку CDS запоминает (кэширует) данные на клиенте, а тебе нужно не это.


 
ildarkh   (2007-01-18 19:35) [9]

я изменил исходник по вашим советам, теперь процедура выглядит так
procedure TSelectInserts.SelInsExec(selins: IXMLSelectInsertType);
var i: integer;
repwith: string;
errstr: string;
TD: TTransactionDesc;
begin
try
Application.ProcessMessages;
TD.TransactionID := 1;
TD.IsolationLevel := xilREADCOMMITTED;
db2.StartTransaction(TD);
errstr := selins.Select.Query;
self.SelInsWork := 1;

//db1.SQLClientDataSet.PacketRecords := 10000;
//db1.SQLClientDataSet.FetchOnDemand := false;

db1.SelectQuery(selins.Select.Query, selins.Select.Params);
self.SelInsWork := 2;
i:=0;
//while not db1.SQLDataSet.Eof do
 begin
 db1.SQLDataSet.First;
 //if db1.SQLDataSet.RecordCount > 0 then
 //for i:=1 to db1.SQLClientDataSet.RecordCount do
 while not db1.SQLDataSet.Eof do
   begin
   inc(i);
   self.InsProgressNum := i;
   errstr := selins.Insert.Query;
   if (i >= 1000 )and (i mod 1000 = 0) then
     begin
     db2.Commit(TD);
     db2.StartTransaction(TD);
     end;
   db2.UpdateQuery(selins.Insert.Query, selins.Fields, db1.DataSource.DataSet.Fields);
   db1.SQLDataSet.Next;
   Application.ProcessMessages;
   end;
 if db1.SQLDataSet.RecordCount > 0 then
 for i:=0 to selins.Select.Params.Count-1 do
   begin
   repwith := selins.Select.Params.Param[i].Replacewith;
   if(repwith <> "") then
      selins.Select.Params.Param[i].Text := db1.DataSource.DataSet.Fields.FieldByName(repwith).AsString;
 end;
 //db1.SQLClientDataSet.GetNextPacket;
end;
db2.Commit(TD);
xmldoc.SaveToFile(ExtractFilePath(ParamStr(0)) + "XML.xml");
except on e: Exception do
 begin
 db2.Rollback(TD);
 Logger.Write(3, e.Message + ": " + errstr);
 end;
end;
self.SelInsWork := 0;
end;

Исключения, как видите перехватываются и журналируются. В этой процедуре есть вызов другой процедуры, UpdateQuery, которая записывает данные в БД-получатель
procedure TMSQLConnection.UpdateQuery(query: string; XMLfields: IXMLFieldsType; SQLfields: TFields);
var i: integer;
values: string;
begin
{self.SQLClientDataSet.Close;
self.SQLClientDataSet.CommandType := ctQuery;
self.SQLClientDataSet.CommandText := query;
self.SQLClientDataSet.Execute;}
try
 query := query + "(";
 values := " values (";
 for i:=0 to XMLFields.Count-1 do
   begin
   query := query + XMLFields.Field[i].Db2;
   if(XMLFields.Field[i].Db1 <> "") then
       values := values + #39 + SQLfields.FieldByName(XMLFields.Field[i].Db1).AsString + #39
   else if(XMLFields.Field[i].Value <> "") then
     values := values + #39 + XMLFields.Field[i].Value + #39
   else values := values + XMLFields.Field[i].Func;
   if(i < XMLFields.Count-1) then
     begin
     query := query + " , "; values := values + " , ";
     end;
   end;
 query := query + ")";
 values := values + ")";

 self.SQLDataSet.Close;
 self.SQLDataSet.CommandText := query + values;
 Logger.Write(2, query + values);
 self.SQLDataSet.ExecSQL(false);

except on e: Exception do
 begin
 Logger.Write(3, e.Message + ": " + query + values);
 end;
end;
end;

Эта вызываемая процедура нормально срабатывает в случае небольшой выборки(или возможно по другой причине). Однако в случае большой выборки, которую я упоминал вначале в первой процедуре вываливаются циклически окошки с ошибкой "DBX Error: Operation Not Supported.", не смотря на try...exept. Данные в БД не заносятся, хотя во второй процедуре исключения нет.


 
Desdechado ©   (2007-01-18 21:03) [10]

Такое засорение кода - ужас!
Отладчиком пользоваться умеешь?

ЗЫ зачем такое количество выворотов? там все просто, как рельсы, должно быть


 
ildarkh   (2007-01-19 09:27) [11]

Может есть какие-то более конкретные рекомендации? Отладчиком пользоваться умею, иначе как бы я написал предыдущий пост.


 
ANB ©   (2007-01-19 10:41) [12]


> Может есть какие-то более конкретные рекомендации?

Есть. Выкинуть все нафиг и написать заново. Код перекачки из БД в БД - максимум 10 строк (если таблицы одинаковой структуры и данные переливаются один в один, при этом список полей заранее известен, т.е. запросы на чтение и вставку можно подготовить заранее).


 
Desdechado ©   (2007-01-19 10:49) [13]

> Отладчиком пользоваться умею, иначе как бы я написал предыдущий пост.
Не видно. Место ошибки не указал, условия ее возникновения слишком расплывчаты.


 
Sergey13 ©   (2007-01-19 11:01) [14]

> [11] ildarkh   (19.01.07 09:27)

А DataPump не пробовал?


 
ildarkh   (2007-01-19 12:15) [15]


> > Отладчиком пользоваться умею, иначе как бы я написал предыдущий
> пост.
> Не видно. Место ошибки не указал, условия ее возникновения
> слишком расплывчаты.


db1.SQLDataSet.Next;
Application.ProcessMessages;

В этом фрагменте происходит вылет, о котором я выше говорил


> Есть. Выкинуть все нафиг и написать заново.
>

Надо исправить то, что есть, извини



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2007.04.08;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.056 c
15-1173878618
zdm
2007-03-14 16:23
2007.04.08
проверка MaskEdit на пустое значение


4-1163810143
Gero
2006-11-18 03:35
2007.04.08
Получение смещения для DC при вызове ExtTextOut


6-1161707045
Max.66RUS
2006-10-24 20:24
2007.04.08
Отправка почты...


15-1173842494
Slider007
2007-03-14 06:21
2007.04.08
С днем рождения ! 14 марта


15-1173879454
Knight
2007-03-14 16:37
2007.04.08
Дайте пару советов по установке...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский