Подвисание программы при записи в базу

Обсуждение возникших проблем, предложений и ошибок MyDAC компонентов
Закрыто
Sanya111
Сообщения: 26
Зарегистрирован: Пн 02 июл 2012 14:07

Подвисание программы при записи в базу

Сообщение Sanya111 » Пн 02 июл 2012 14:25

Привет.
Хочу пользоваться вашими компонентами, но не во всем еще могу разобраться.
Подскажите, пожалуйста из-за чего может подвисать мое окно?
Происходит это так:
1) Каждые 2-3 секунды делаю INSERT примерно 100-300 записей.
2) Процессор работает на 90% процентов и окно не виснет. Скорость записи высокая.
3) Но после ~20.000 строк в базе загрузка процессора резко падает до обычной 10% и окно ни переместить толком ни закрыть нельзя и импорт данных становится раз в 100 медленней.
В общем программа едва подает признаки жизни. Записываю строки длиной 1000-2000 символов.
Не пинайте, пожалуйста сильно, подскажите как вообще в теории решается такая задача и правильно ли я делаю или проблема может быть в чем-то другом?

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

Form1.MyQuery1.SQL.Text := 'select * from rd';
 Form1.MyQuery1.Open;
 Form1.MyConnection1.StartTransaction;
  try
    for i1:=0 to ForInsertPrIndex-1 do
    begin
      Form1.MyQuery1.Insert;
      Form1.MyQuery1.FieldByName('name_id').AsString:=ForInsertPrNAME[0,i1];
      Form1.MyQuery1.FieldByName('limit_id').AsInteger:=strtoint(ForInsertPrNAME[1,i1]);
      Form1.MyQuery1.FieldByName('number_id').AsInteger:=strtoint(ForInsertPrNAME[2,i1]);
      Form1.MyQuery1.FieldByName('dateM_id').AsInteger:=strtoint(ForInsertPrNAME[3,i1]);
      Form1.MyQuery1.FieldByName('dateG_id').AsInteger:=strtoint(ForInsertPrNAME[4,i1]);
      Form1.MyQuery1.FieldByName('prM_id').AsString:=ForInsertPrMOG[i1];
      Form1.MyQuery1.FieldByName('prS_id').AsString:=ForInsertPrSDELAL[i1];
      Form1.MyQuery1.Post;
    end;
    Form1.MyConnection1.Commit;
    Form1.MyQuery1.Close;
  Except
    Form1.MyConnection1.Rollback;
    raise;
  end; 

Создаю таблицу

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

Form1.MyConnection1.ExecSQL('create table if not exists RD (name_id text(50) not null,'
+'limit_id integer not null,'
+'number_id integer not null,'
+'dateM_id integer not null,'
+'dateG_id integer not null,'
+'prM_id text,'
+'prS_id text, primary key(name_id(50), limit_id, number_id, dateM_id, dateG_id))',[]);
Я храню в базе значения в виде строк (~2000 символов).
Я получаю строку из базы, разбиваю ее, раскидываю по массивам и работаю с этими значениями.
Дело в том, что мне если и нужна строка, то мне нужны все значения из нее.
Может все таки создать таблицу с большим количеством колонок?
... но мне все равно нужны будут значения из всех колонок.
Даже не знаю что делать :(

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: Подвисание программы при записи в базу

Сообщение AndreyZ » Вт 03 июл 2012 11:00

Здравствуйте,

При использования Вашего подхода данные хранятся в оперативной памяти на клиентском компьютере что негативно сказывается на производительности процесса записи новых данных. Для улучшения производительности Вам следует:
- использовать INSERT запрос;
- препарировать (Prepare) INSERT запрос на сервере перед его выполнением;
- уменшить количество полей входящих в первичный ключ, оставить только поля которые уникально идентифицируют запись. Самым простым решением будет добавить автоинкремент поле и только его включить в первичный ключ.
Следующий пример демонстрирует данный подход:

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

procedure TMainForm.Button1Click(Sender: TObject);
begin
  MyConnection1.ExecSQL('CREATE TABLE IF NOT EXISTS RD'
  + '(id INTEGER NOT NULL AUTO_INCREMENT,' // автоинкремент поле
  + 'name_id TEXT(50) NOT NULL,'
  + 'limit_id INTEGER NOT NULL,'
  + 'number_id INTEGER NOT NULL,'
  + 'dateM_id INTEGER NOT NULL,'
  + 'dateG_id INTEGER NOT NULL,'
  + 'prM_id TEXT,'
  + 'prS_id TEXT,'
  + 'PRIMARY KEY (id))' // первичный ключ по автоинкремент полю
  + 'ENGINE = INNODB', []); // INNODB для поддержки транзакций
end;

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

procedure TMainForm.Button2Click(Sender: TObject);
var
  i: integer;
begin
  MyQuery1.SQL.Text := 'INSERT INTO RD'
                     + '(name_id, limit_id, number_id, dateM_id, dateG_id, prM_id, prS_id)'
                     + 'VALUES'
                     + '(:name_id, :limit_id, :number_id, :dateM_id, :dateG_id, :prM_id, :prS_id)';                     
  MyQuery1.Prepare; // препарируем INSERT запрос на сервере
  if not MyConnection1.InTransaction then
    MyConnection1.StartTransaction;
  try
    for i := 1 to 10 do begin
      MyQuery1.ParamByName('name_id').AsString := IntToStr(i);
      MyQuery1.ParamByName('limit_id').AsInteger := i;
      MyQuery1.ParamByName('number_id').AsInteger := i;
      MyQuery1.ParamByName('dateM_id').AsInteger := i;
      MyQuery1.ParamByName('dateG_id').AsInteger := i;
      MyQuery1.ParamByName('prM_id').AsString := IntToStr(i);
      MyQuery1.ParamByName('prS_id').AsString := IntToStr(i);
      MyQuery1.Execute;
    end;
    MyConnection1.Commit;
  except
    MyConnection1.Rollback;
    raise;
  end;
end;
Также Вы можете использовать компонент TMyLoader который служит для быстрой загрузки данных на сервер. Работа компонента TMyLoader основана на генерации INSERT запросов которые вставляют несколько записей одновременно (количество записей контролируется свойством TMyLoader.RowsPerQuery). Следующий пример демонстрирует использование компонента TMyLoader:

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

procedure TMainForm.Button1Click(Sender: TObject);
begin
  MyLoader1.TableName := 'RD';
  if not MyConnection1.InTransaction then
    MyConnection1.StartTransaction;
  try
    MyLoader1.Load;
    MyConnection1.Commit;
  except
    MyConnection1.Rollback;
    raise;
  end;
end;

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

procedure TMainForm.MyLoader1PutData(Sender: TDALoader);
var
  i: integer;
begin
  for i := 1 to 10 do begin
    Sender.PutColumnData('name_id', i, IntToStr(i));
    Sender.PutColumnData('limit_id', i, i);
    Sender.PutColumnData('number_id', i, i);
    Sender.PutColumnData('dateM_id', i, i);
    Sender.PutColumnData('dateG_id', i, i);
    Sender.PutColumnData('prM_id', i, IntToStr(i));
    Sender.PutColumnData('prS_id', i, IntToStr(i));
  end;
end;
За дополнительной информацией о компоненте TMyLoader обратитесь пожалуйста к документации MyDAC.

Sanya111
Сообщения: 26
Зарегистрирован: Пн 02 июл 2012 14:07

Re: Подвисание программы при записи в базу

Сообщение Sanya111 » Вт 03 июл 2012 11:46

AndreyZ,
огромное Вам спасибо за помощь!!
Ответил Вам и на этом форуме http://www.sql.ru/forum/actualthread.aspx?tid=952716
Буду рад подарить Вам $20 moneybookers в знак благодарности!!

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: Подвисание программы при записи в базу

Сообщение AndreyZ » Вт 03 июл 2012 13:21

Я рад что смог помочь. Если у Вас возникнут дальнейшие вопросы по MyDAC, пишите нам.

Закрыто