Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Lazarus SQL многопоточность INSERT / 25 сообщений из 31, страница 1 из 2
15.04.2019, 14:55
    #39801548
Moneo
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Добрый время суток. Только начал изучать многопоточность, сейчас мне нужно делать INSERT в одну таблицу большим количеством потоков, так как очень большой объем данных. Использую Lazarus, SQL server 2014, прочитал что нужно создавать для каждого потока свои компоненты подключения и прочитал вики страницу по использованию потоков по паскалю.

После этого сделал 2 потока и из метода Execute только вызываю одну и туже процедуру в которой идет обработка строк, создаются динамически компоненты подключения, в потоках указана 1 процедура в которой частями получаются данные с стороннего сервера, обрабатываются строки, происходит вставка INSERT SQL. В результате получаю ошибку RUNTIME 204, когда 1 поток, то все работает нормально. В процедуре вставки есть еще локальные строковые переменные процедуры (для будущей вставки) которые копируются из огромной строки и они в потоках не пересекаются, но SQL Insert дает сбой при 2 потоках и более. Привожу код, что мне надо сделать чтобы исправить ситуацию? Прошу ссылки на примеры использования баз данных в потоках и\или конкретные советы по задаче. Как правильно использовать переменные и компоненты в потоках - должны быть уникальные имена компонентов или 2 потока могут ссылаться на одну и туже внешнюю процедуру и данные не будут сбиваться (пример что будет если 2 потока ссылаюся на процедуру с sql_db:=tsqlquery.create(self) с разными запросами - будет ли это корректно работать? Потоки в программе только вставляют данные в одну таблицу, с интерфейсом не соприкасаются.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
procedure Mythread.Execute;
begin
form1.GET_MAAINDATA('250','0','1');
end;

procedure Mythread2.Execute;
begin
form1.GET_MAAINDATA('500','250','2');
end;   

procedure TForm1.GET_MAAINDATA(limit,offset,numpotok:string);
begin    
//ПОЛУЧИЛ СОРС СТРАНИЦЫ С ИНТЕРНЕТА
temp:=PChar(HTTPs.Document.Memory);

while pos(',{"uuid"',temp)<>0 do
begin
get_main_data2(copy(temp,1,pos(',{"uuid"',temp)-1));
delete(temp,1,pos(',{"uuid"',temp)+9);
end; 

end;

function TForm1.get_main_data2(input:string):string;
var
SQL_Database:tsqlconnector;
SQL_Transaction:tsqlTransaction;
SQL_Query:tsqlquery;
SQL_Datasource:tDatasource; 
//СТРОКОВЫЕ ПЕРЕМЕННЫЕ ДЛЯ ОБРАБОТКИ
begin

SQL_Database:=tsqlconnector.Create(self);
SQL_Transaction:=tsqlTransaction.Create(self);
SQL_Datasource:=tDatasource.Create(self);
SQL_Query:=tsqlquery.Create(self);

SQL_Database.connectortype:='MSSQLServer';
SQL_Database.DatabaseName:='test';
SQL_Database.HostName:='хост';
SQL_Database.username:='пользователь';
SQL_Database.password:='пароль';
SQL_Database.Transaction:=SQL_Transaction;
SQL_Transaction.database:=SQL_Database;
SQL_Query.database:=SQL_Database;
SQL_Query.Transaction:=SQL_Transaction;
SQL_Query.PacketRecords:=-1;
SQL_Datasource.dataset:=SQL_Query;

SQL_Database.connected:=true;  

//ОБРАБОТКА СТРОК

//SQL INSERT ВСТАВКА СТРОК В ТАБЛИЦУ

end;
...
Рейтинг: 0 / 0
15.04.2019, 15:17
    #39801558
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Moneo
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
//ПОЛУЧИЛ СОРС СТРАНИЦЫ С ИНТЕРНЕТА
temp:=PChar(HTTPs.Document.Memory);

while pos(',{"uuid"',temp)<>0 do
begin
get_main_data2(copy(temp,1,pos(',{"uuid"',temp)-1));
delete(temp,1,pos(',{"uuid"',temp)+9);
end; 


На вскидку: оба потока работают с одним участком памяти.

ЗЫ. На какой строке возникает ошибка lazarus не показывает?
...
Рейтинг: 0 / 0
15.04.2019, 15:19
    #39801561
Cobalt747
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Многопоточность нужна не для ускорения!
...
Рейтинг: 0 / 0
15.04.2019, 15:31
    #39801568
Moneo
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Ошибка при открытии SQL, перед вставкой идет открытие на проверку наличия ID в таблице, если нету, то вставляется.
...
Рейтинг: 0 / 0
15.04.2019, 15:33
    #39801569
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Еще и коннект на каждый чих стартует, когда достаточно при старте потока его создать, а при окончании уже уничтожить.
...
Рейтинг: 0 / 0
15.04.2019, 15:40
    #39801575
Moneo
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Cobalt747,

ну тогда поясните почему в итоге ускоряется обработка данынх
...
Рейтинг: 0 / 0
15.04.2019, 15:41
    #39801576
Moneo
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
wadman,

в каком месте он стартует на каждый чих. Расскажите как правильно в данном случае вставку в потоках делать?
...
Рейтинг: 0 / 0
15.04.2019, 15:43
    #39801578
Moneo
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Мой главный вопрос - как избежать написание однотипного кода при потоках и как работать с запросами к одной таблице базы данных на вставку, обновление?
...
Рейтинг: 0 / 0
15.04.2019, 15:48
    #39801585
Moneo
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Может мне нужно создавать компоненты SQL в execute каждого потока отдельно, а потом их передать функции get_main_data2 в параметрах - это способствует разделению подключений к базе и не нужно будет передавать и обрабатывать кучу строк?
...
Рейтинг: 0 / 0
15.04.2019, 16:49
    #39801652
goldmi45
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Moneo
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
procedure TForm1.GET_MAAINDATA(limit,offset,numpotok:string);
begin    
//ПОЛУЧИЛ СОРС СТРАНИЦЫ С ИНТЕРНЕТА
temp:=PChar(HTTPs.Document.Memory);

while pos(',{"uuid"',temp)<>0 do
begin
  get_main_data2(copy(temp,1,pos(',{"uuid"',temp)-1)); // Вот это вызывается на каждый чих, а в ней создаётся коннект и др.
  delete(temp,1,pos(',{"uuid"',temp)+9);
end; 

end;

function TForm1.get_main_data2(input:string):string;
var
SQL_Database:tsqlconnector;
SQL_Transaction:tsqlTransaction;
SQL_Query:tsqlquery;
SQL_Datasource:tDatasource; 
//СТРОКОВЫЕ ПЕРЕМЕННЫЕ ДЛЯ ОБРАБОТКИ
begin
  //... skip
end;
...
Рейтинг: 0 / 0
15.04.2019, 18:28
    #39801713
Gator
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
А я бы посоветовал посмотреть на план исполнения в MSSQL,
Профайлер что говорит?
Про блокировки таблицы, про сам запрос. (может, HINT нужно добавить?)
Разобраться, наконец, с блокировками. Transactionlog позырить...
__________
ну и запроса INSERT/UPDATE не видно пока.
...
Рейтинг: 0 / 0
15.04.2019, 20:40
    #39801760
энди
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
для заливки данных есть bcp, в круйнем случае есть специальный интерфейс для быстрой заливки данных в таблицы, на память сейчас не вспомню но посмотрите доку на TLoader у SDAC, он его использует, в доке сказано через какой интерфейс загоняет. По итогу там десятки тысяч записей в секунду получаются потому что льются сразу данные в таблицу без всяких insert
...
Рейтинг: 0 / 0
15.04.2019, 22:16
    #39801776
Gator
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
энди,

bcp Действительно хороша, но она ведь тупо игнорирует триггеры, ключи и пр. А ещё фигатень в журнале транзакций.
Но если залить таблицу(ы) с нуля, - очень впечатляет!. Зато потом надо включить триггеры, констрейнты и перестроить индексы. На этом время и схомячится.
...
Рейтинг: 0 / 0
15.04.2019, 22:23
    #39801778
Gator
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Gator,

Например, моя Собачья База весит всего 30 ГБ, и там всего две больший таблицы Dogs & Person + линк между ними. Reindex для меня - жесть!
...
Рейтинг: 0 / 0
15.04.2019, 22:32
    #39801781
Dmitry Arefiev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Array DML
...
Рейтинг: 0 / 0
15.04.2019, 22:36
    #39801782
Gator
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Cobalt747Многопоточность нужна не для ускорения!А для чего ещё?
Именно для ускорения обработки одних и тех же данных. Ну или совмещения обработки разных данных
...
Рейтинг: 0 / 0
15.04.2019, 22:45
    #39801786
Gator
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Dmitry ArefievArray DMLНасколько мои тупые мозги осознали, в MSSQL физически это реализуется через выборки/временные таблицы. В чём выгода?
...
Рейтинг: 0 / 0
15.04.2019, 22:55
    #39801788
Док
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Moneoсейчас мне нужно делать INSERT в одну таблицу большим количеством потоков, так как очень большой объем данных.
как-то странно ты потоки используешь: из execute доп.потока вызываешь процедуры основного :)
Может сделать примерно так?
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
type
  TMythread = class(TThread);
  ....
  public 
    сonstructor Create(<параметры подключения/инсерта и проч.проч.>)
  ...
  end;
procedure TMythread.Execute;
begin
//создал подключение к БД

//ПОЛУЧИЛ СОРС СТРАНИЦЫ С ИНТЕРНЕТА
... твой код

//ОБРАБОТКА СТРОК
... твой код
//SQL INSERT ВСТАВКА СТРОК В ТАБЛИЦУ
... твой код

//убил подключение к БД
end;

procedure TForm1.CreateInsertTask();
var TempThread: TMythread;
begin    
  TempThread:= TMythread.Create(<параметры подключения/инсерта и проч.проч.>);

  // после отработки доп.поток умирает или убивается вручную
end;

...
Рейтинг: 0 / 0
15.04.2019, 23:24
    #39801793
Dmitry Arefiev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
GatorDmitry ArefievArray DMLНасколько мои тупые мозги осознали, в MSSQL физически это реализуется через выборки/временные таблицы. В чём выгода?
В сокращении накладных расходов на один за одним вызовом. Можно и TVP - где-то быстрее (зависит, может быть и много).
BCP - наибыстрейший, но с ним не спрашивай о консистентности :)
...
Рейтинг: 0 / 0
15.04.2019, 23:56
    #39801795
Vlad F
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Dmitry ArefievArray DML
Дмитрий, ты сказуемое пропустил, как обычно.))
Однако, было бы очень любопытно, если бы кто-нибудь сравнил многопоточную вставку в MS SQL
через Array DML и многопоточный же Bulk Inset посредством все того же Fire DAC.
...
Рейтинг: 0 / 0
16.04.2019, 00:12
    #39801798
Gator
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Dmitry Arefiev,

И всё равно всё сводится к временным таблицам IMHO
Допустим, загрузка данных в таблицы. Затратность навскидку
Метод Данные КонсистентностьBCP 10%90%долгий реиндекс и т.п.TVP 99%1%индексы на пустых таблицах строятся моментально
Т.е. исходные данные надо как-то формировать заранее, а затем их писать в таблицы
...
Рейтинг: 0 / 0
16.04.2019, 00:39
    #39801806
Gator
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
...
Рейтинг: 0 / 0
16.04.2019, 10:18
    #39801915
энди
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
...
Рейтинг: 0 / 0
16.04.2019, 13:38
    #39802105
Moneo
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Док,спасибо за наводку и всем остальным за ссылки. Буду пробовать
...
Рейтинг: 0 / 0
17.04.2019, 16:31
    #39802931
Moneo
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Lazarus SQL многопоточность INSERT
Док, сделал так как вы говорили, но при получении большого числа страниц новые POST запросы валяться с ошибкой: Resultcode 0, Resultstring пусто - какая-то часть страниц получается хорошо, но большая часть сыпит ошибки, пробовал делать задержку в виде sleep, но не помогает.

В коде идет получение страниц с сервера за 120 дней, в потоке получение кода страницы и сохранение в stringlist, потом txt. Объем каждой страницы от 200кб до 8мб. Скажите есть ли вообще смысл использовать потоки для выкачивания такого объема информации, ведь на сеть ограничение 100 мегабит и ошибки почему-то сыпит.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
procedure TForm1.Button2Click(Sender: TObject);
var
 MyThread : TMyThread;
 i,l:integer;
 k:tdate;
 YY,MM,DD : Word;
 day,month:string;
begin
k:=strtodate('17.04.2019');

for i:=120 downto 1 do
begin
k:=k-1;
DecodeDate(k,YY,MM,DD);
day:=inttostr(DD);
if length(day)=1 then day:='0'+day;
month:=inttostr(MM);
if length(month)=1 then month:='0'+month;

MyThread := TMyThread.Create(True,'9500','0',inttostr(i),'{"field":"dateCreatedFrom","value":"'+inttostr(YY)+'-'+month+'-'+day+'"},{"field":"dateCreatedTo","value":"'+inttostr(YY)+'-'+month+'-'+day+'"}',inttostr(YY)+'-'+month+'-'+day); // With the True parameter it doesn't start automatically
if Assigned(MyThread.FatalException) then
  raise MyThread.FatalException;
MyThread.Start;
end;
        



Код потоков:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
procedure TMyThread.Execute;
var
i:integer;
temp:string;
HTTPs: THTTPSend;
Data: TStringStream;
uuid,tempout: string;
exportfull: tstringlist ;
starttime,endtime:ttime;
begin
starttime:=now;
exportfull:= tstringlist.create;
exportfull.text:='';

https:=thttpsend.Create;
HTTPs.UserAgent := 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4';
https.KeepAlive:=true;
HTTPs.Protocol:= '1.1';
HTTPs.Timeout:= 10000; // 45 seconds
HTTPs.MimeType :='application/json;charset=UTF-8';
HTTPs.Headers.Addstrings(['pwt:1937f8f982e64da2b9e0c6d5fbe889da']);

Data := TStringStream.Create('');
Data.WriteString('{"lang":"rus","apiName":"contragent","apiPath":"/contragentEk5/getFilterData","limit":'+limit+',"offset":'+offset+',"fields":['+fields+',{"field":"type","value":"ur"}],"columns":["ek4Id","country","city","name","type","subdivisionName","kindOfActivity","masterCity","note"],"sort":[]}');
HTTPs.Document.LoadFromStream(Data);
Data.Free;

if not HTTPs.HTTPMethod('POST','https://contragent.cdek.ru/api/preback')  then
    MessageDlg('POST Ошибка '+ IntToStr(HTTPs.Resultcode)+#13#10+HTTPs.Resultstring,mtError,[mbok],0) else
    temp:= PChar(HTTPs.Document.Memory);

HTTPs.free;

exportfull.text:=temp;
exportfull.SaveToFile(ExtractFilePath(Application.ExeName)+'out\'+exportname+'_ur.txt');
exportfull.free;
endtime:=now;
exportfull.free;
form1.memo1.lines.add('Complete '+numpotok+': '+timetostr(endtime-starttime)); 
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Lazarus SQL многопоточность INSERT / 25 сообщений из 31, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]