Net-Base Магазин

28.07.2026

FireDAC: Bulk-Insert помоћу Array DML и прецизно руковање грешкама по реду

FireDAC Array DML значајно убрзава Bulk-Inserts — док се не појави прва грешка ограничења. Овај практични чланак показује како да изградиш Bulk-Insert помоћу Array DML тако да за сваки ред добијеш робустне информације о грешци, да прецизно управљаш транзакцијама и да у продукцији смислено дебагујеш...

28.07.2026

Од теме часописа до пројектне праксе

Одговарајуће странице услуга и техничке странице за чланак

Ein BDE-Ablosung mit nativer Anbindung Bulk-Insert mit Array DML je često najbrži način da se veliki broj zapisa ubaci u bazu podataka: umesto hiljadu pojedinačnih INSERT-ova veže se niz parametara i šalje odjednom na server. U praksi se problem brzo pojavi: jedan zapis krši Unique-Index, polje označeno kao NOT NULL je prazno, jedan Foreign Key ne odgovara — i iznenada nije jasno koja je red u batch-u pokvario ceo unos, da li je deo već upisan i kako bezbedno nastaviti bez stvaranja nekonzistentnosti podataka.

Upravo o tome je reč ovde: kako da koristiš Array DML tako da dobiješ pouzdane informacije o greškama po redu, zadržiš kontrolu nad transakcijom i u radu možeš da rekonstrušeš šta se dogodilo. Fokus nije na akademskom prelistavanju API-ja, već na rubnom slučaju koji se u stvarnim importima redovno javlja: veliki batch, nekoliko pokvarenih redova, ali i dalje želiš brzinu.

FireDAC Bulk-Insert mit Array DML: Warum Array DML beim Bulk-Insert überhaupt lohnt

Passendes Inline-Motiv zum Abschnitt FireDAC Bulk-Insert mit Array DML: Warum Array DML beim Bulk-Insert überhaupt lohnt
Одговарајућа илустрација за одељак "BDE-Ablosung mit nativer Anbindung Bulk-Insert mit Array DML: Warum Array DML beim Bulk-Insert überhaupt lohnt" визуелно продубљује садржај.

Array DML (Data Manipulation Language) bedeutet in FireDAC: Du bindest Parameter nicht als Einzelwert, sondern als Array. FireDAC sendet dann (je nach Treiber/DB) weniger Roundtrips, kann serverseitig effizienter arbeiten und reduziert den Overhead im Client drastisch. Das ist in drei Situationen besonders relevant:

  • ETL- und Importstrecken: CSV/XML/JSON rein, Normalisierung/Mapping, dann in Staging- oder Zieltabelle.
  • Schnittstellen-Puffer: REST- oder MQ-Payloads werden gesammelt und periodisch persistiert.
  • Protokoll-/Event-Tabellen: viele kleine Inserts, bei denen Latenz dominiert.

Der Gewinn kommt aber nicht gratis. Mit Array DML verschiebst du Komplexität von „viele einzelne Statements“ zu „ein Statement mit vielen Zeilen“. Das ist gut für Performance, aber anspruchsvoller für Fehlerdiagnose, Transaktionslogik und Wiederanlauf.

Der typische Randfall: Ein Batch, eine kaputte Zeile

Der Klassiker im Betrieb: Du importierst 50.000 Zeilen. Du wählst eine ArraySize von 1.000, weil du nicht für jede Zeile einen Roundtrip willst. Batch 17 scheitert. Die DB meldet nur „duplicate key“ oder „violates foreign key constraint“. In der UI oder im Service-Log steht dann oft nur: „ExecSQL failed“.

Ohne sauberes Error-Handling passieren dann meist zwei schlechte Dinge:

  • Du wirfst den ganzen Batch weg, obwohl 999 von 1.000 Zeilen ok wären.
  • Du fällst auf Einzel-Inserts zurück und verlierst den Performancevorteil dauerhaft.

Cilj je treći put: očuvati Batch-performanse, ali evidentirati svaku grešku precizno (indeks reda, vrednosti ključeva, tekst greške DB-a) i po želji potvrditi „good rows“ – u zavisnosti od toga koliko su kritični konzistentnost i idempotencija (više izvršavanja bez duplog efekta) u tvom procesu.

FireDAC Array DML: Die relevanten Stellschrauben (ohne Mythen)

Za bulk-insert sa Array DML u praksi su uvek iste ključne stavke presudne:

1) ArraySize und Batch-Größe

ArraySize (kod TFDQuery/TFDCommand) određuje koliko „redova“ FireDAC se obradi u jednom pozivu. Veće nije automatski bolje. Preveliko znači: više memorije na klijentu, veći saobraćaj na mreži, veće lock-ove/log-opterećenje na serveru i u slučaju greške veći opseg posledica. Za robusne importa često je veličina serije između 200 i 2.000 dobar početni parametar, u zavisnosti od broja kolona, BLOB-ova i latencije.

2) Transaktionsgrenze

Potrebna ti je jasna odluka: Commit po batch-u ili Commit za ceo import. To nije stvar ukusa, već operativna odluka:

  • Commit po batch-u: ograničava zaključavanja i transakcioni log, olakšava RESTart, ali međurezultati su vidljivi (u zavisnosti od nivoa izolacije). Greška u batch-u 17 ostavlja batch-e 1–16 u sistemu.
  • Commit na kraju: „sve ili ništa“, konzistentnije u poslovnom smislu, ali kod velikih količina rizikuješ dugačke lock-ove, veliki rollback i u slučaju greške sve je izgubljeno.

Za mnoge interfejse i import-procese „Commit po batch-u“ je realističnija operativna strategija – ali samo ako imaš idempotenciju i strategiju za duplikate dobro uređenu (npr. preko prirodnih ključeva, Upserts ili Import-ID).

3) UpdateOptions und Prepared Statements

Kod ponavljanih batch-eva isplati se ostaviti statement pripremljenim. „Prepare“ znači: FireDAC omogućava DB-u da parsira/kompajlira statement i ponovo ga koristi. U zavisnosti od DB-a to može imati opipljiv efekat, posebno pri visokoj frekvenciji. Važno ovde nije neki „Trick 17“, već: konsekventno ponovno korišćenje istog Query-objekta (ili istog TFDCommand) i stabilni tipovi parametara.

Robusno rukovanje greškama po redu: šta ti zaista treba

Ako želiš da rukuješ greškama „po redu“, treba ti tri stvari:

  1. Mapiranje: Koji Array-indeks (0..N-1) je podbacio?
  2. Kontekst: Koje poslovne vrednosti ima taj red (npr. eksterni ID, broj kupca, timestamp)?
  3. Kontrola: Šta radiš posle? Prekidaš, preskačeš samo loše redove ili deliš batch?

FireDAC može, u zavisnosti od drajvera, vratiti greške po elementu niza. U praksi to nije „uvek dostupno“. Moraš računati na to da neke baze/driver-i prijave samo prvu grešku ili da greška u batch-u spreči izvršavanje preostalih. Upravo zato je robusan obrazac obično dvostepen:

  • Faza A: Pokušaj batch kao Array DML.
  • Faza B: Ako batch ne uspе, podeli ga (na pola) ili kontrolisano pređi na pojedinačne redove – ali samo za taj batch – i loguj precizno.

To zvuči kao dodatni rad, ali u import-putanjama je razlika između „noću u 02:00 sve stane“ i „import prođe, 7 redova završi u listi grešaka“.

Ein praxistaugliches Muster: Batch zuerst, dann gezielt isolieren

Следећи образац се показао као успешан за софтверска решења блиска процесу, у којима је квалитет података мешовит:

Корак 1: Спаковати податке у batch-структуру (укљ. контекст грешке)

Сачувајте податке који се увозе не само као сирове вредности, већ са минималним контекстом: спољни ID, број реда из извора, евентуално hash/checksumu. Ово није „Nice to have“: у случају грешке не желите да прво поново парсирате CSV да бисте утврдили шта није у реду.

Корак 2: Покренути Array DML

Подесите ArraySize на дужину batch-а, вежите параметре као низове и позовете ExecSQL. Важно: типови параметара треба да буду стабилни (нпр. за нумеричка поља не вежите понекад као String, понекад као Integer), иначе база података производи implicitне конверзије или FireDAC мора да претвара по елементу.

Корак 3: У случају грешке — сузите batch уместо да га слепо понављате

Ако ExecSQL не успе, имате две робусне опције:

  • Binary Split (преполовити): поделити batch на две половине, сваку половину поново покушати као Array DML. Ово понављате док не останете на малој групи коју можете проверити појединачно. Предност: задржите већину перформанси ако су само појединачни редови неисправни. Недостатак: више логике, и при системским грешкама (нпр. погрешан тип податка) мало помаже.
  • Fallback на појединачне редове за овај batch: подесите ArraySize=1 (или вежите појединачне вредности) и извршавате ред по ред, логујете грешке и настављате. Предност: једноставно, гарантује по реду. Недостатак: у овом batch-у губите брзину.

У пракси комбинујем оба приступа: прво 1–2 пута раздвојити (да брзо пропустите „добре блокове“), а затим код малих остатка прећи на појединачне редове да бисте логовали јасне информације о грешкама.

Објекти грешака и поруке: шта треба да извучете из FireDAC

FireDAC обавија грешке базе у Exceptions (типично EFDDBEngineException) са детаљним информацијама. За рад су важна три нивоа:

  • DB код грешке (специфично за БД): нпр. SQLSTATE код PostgreSQL, Error Number код SQL Server-а.
  • Име ограничења/објекта: често садржано у тексту грешке (Unique-Index, FK-Constraint).
  • Контекст упита: табела, операција, евентуално вредности параметара (опрезно са подацима који се односе на појединца).

Ако желите да логујете по реду, у случају грешке морате такође идентификовати ред. FireDAC може, у неким случајевима, вратити индекс низа. Међутим, не ослањајте се искључиво на то. Увек додајте сопствени индекс (позицију у batch-у) и за ту позицију логујте најмање један пословни кључ.

Замке које у правим увозима троше време

1) „Био је само један ред“ — али транзакција је већ „dirty“

У зависности од базе података и драјвера, грешка може довести до тога да се цело извршавање упита сматра неуспелим и да транзакција буде у стању у коме морате експлицитно да урадите rollback или у коме даље наредбе неће успети. Посебно код појединих драјвера није поуздано претпоставити да можете „после грешке једноставно наставити“.

Последица: ако радите у транзакцији и batch не успе, стандардни пут је: rollback текућег batch-контекста (или целе транзакције) и онда поновни покушај. То добро одговара приступу „Commit по batch-у“.

2) Autocommit vs. експлицитна транзакција

Ако не покрећете експлицитну транзакцију, често драјвер/провајдер одлучује како он комитује упите. За bulk-увозе то рђео није оно што желите. Експлицитне транзакције вам дају контролу над:

  • трајање закључавања
  • Ponašanje rollback-a
  • Tačke ponovnog pokretanja

I: Eksplizitno ne znači „„ogromna transakcija“. Znači „svesno“.

3) Trigeri, ograničenja i neželjeni efekti

Array DML ubrzava predaju, ali ne automatski rad na serverskoj strani. Ako na ciljnoj tabeli imaš triggere (npr. Audit-Logging, automatsko izračunavanje statusa), onda usko grlo možda uopšte nije INSERT, već kod u triggeru. U tom slučaju batch može imati manje roundtrip-ova, ali CPU na DB-serveru ostaje limitirajući faktor.

Za administratore i tehničke lidere: kod problema sa performansama vredi pogledati Wait Events/Locks i transakcioni log. Bulk-insert je tada često samo okidač, a ne uzrok.

4) Tipovi podataka i implicitne konverzije

Jedan od najčešćih razloga „Zašto je to sporo?“: parametri se vežu kao string, DB po redu kastuje u Integer/Date/Decimal. To je nevidljivo, ali skupo. Za stabilne performanse:

  • Podesiti odgovarajuće tipove parametara (datum kao datum, broj kao broj).
  • Kod decimalnih brojeva obratiti pažnju na zamke lokalizacije (zarez naspram tačke). FireDAC je ovde obično ispravno, ali mešoviti izvori nisu.
  • Unapred razjasniti strategiju vremenskih zona/UTC (timestamps su klasika pri importima).

5) Poruke o greškama su za ljude, a ne za automatizaciju

Usklađeno je pokušavati parsirati tekst greške („duplicate key value violates unique constraint …“). Radite to samo kao poslednju opciju. Bolje su strukturisani kodovi (SQLSTATE, Error Number). Nažalost, ne svi drajveri daju sve jednako dobro. Planiraj zbog toga obe stvari: kod i tekst, plus opcionalno „ime constraint-a iz teksta“, ali bez čvrste zavisnosti.

Debugging-savet: Kako brzo pronaći pokvareni red

Učiniti batch reproducibilnim

Ako import povremeno ne uspeva, treba ti reproduktivnost. Sačuvaj po batch-u malu dijagnostičku datoteku ili log-unos koji sadrži:

  • Broj batch-a i vreme
  • ArraySize i mod transakcije
  • listu poslovnih ključeva (npr. eksterni ID-evi) u batch-u

To često dovoljno da naknadno pokreneš mini-import samo za te ID-e.

Učiniti finalni SQL vidljivim (ali bez curenja podataka)

U debagovanju želiš da znaš: da li je SQL korektan? Da li su parametri pravi? FireDAC nudi Monitoring/Tracing preko FDMoni-Komponenten i Treiber-Logging. U produkciono-sličnim okruženjima važno je:

  • Tracing ciljano omogućiti samo privremeno (zbog performansi i zaštite podataka).
  • Vrednosti parametara logovati samo u sigurnom okruženju ili maskirano.
  • Za lične podatke: u logu samo tehnički ključevi (ID-evi) i bez podataka u jasnom tekstu.

Ako radiš split-test: definiši kriterijume za prekid

Pri binarnom splitovanju ne želiš beskonačno deliti. Postavi donju granicu, npr. „ispod 20 redova prebaci na pojedinačni režim“. I postavi limit koliko grešaka ukupno tolerišeš pre nego što prekineš import (npr. kod sistemskih problema mapiranja). Inače ćeš dobiti beskonačne liste grešaka i blokirati dalju obradu.

Kada se trud zaista isplati (i kada ne)

Array DML sa rukovanjem greškama po redu posebno se isplati kada:

  • Veliki broj redova se obrađuje (hiljade do miliona).
  • Mali broj redova ima greške, ali želiš da obrada i dalje teče.
  • Import mora stabilno da radi u produkciji (npr. noćna obrada, servis bez UI).
  • Trebaš da vratiš listu grešaka poslovnom odeljenju/izvoru (sa referencom na redove).

Мање се исплати ако:

  • ако уносиш само неколико десетина редова (појединачни INSERT-ови су у реду),
  • ако је квалитет података толико лош да 30–50% редова не успева (тада је погоднија стратегија са Staging-табелом),
  • ако ионако користиш DB-нативни поступак за учитавање (нпр. COPY у PostgreSQL, BCP/BULK INSERT у SQL Server) – у том случају Array DML није алат.

Алтернативна архитектура: Staging-табела уместо „директно у циљну“

Ако се редовно суочаваш са мешовитим квалитетом података, чист „INSERT директно у циљну табелу“ често је погрешна одлука. Staging-табела (предфаза) је табела у коју прво технички коректно снимаш податке (по потреби са релаксираним типовима), а тек потом их валидаш и преносиш у циљну табелу.

Предности у раду:

  • Неисправни записи остају сачувани и праћени (укључујући сирове податке).
  • Можеш извршавати валидацију одвојено и понављајуће.
  • Одвајаш пријем интерфејса од пословне обраде.

Array DML је тада често брз пут у Staging-табелу, док се пренос у циљну табелу обавља као сет-базирани SQL (или Stored Procedure). То помера обраду грешака више на страну базе података, што у зависности од организације (DBA-улоге, Deployment) може бити пожељно или непожељно.

Рад и администрација: шта IT-лидери и администратори треба да знају

Мониторинг: стопа грешака и пропусност су кључне метрике

За стабилан рад bulk-импорта две метрике дају више информација од саме „време извршавања“:

  • Пропусност: редова по минути (или по батчу) укључујући пикове/медијану.
  • Стопа грешака: неисправни редови по извршавању, по могућству груписано по класи грешке (Unique, FK, NOT NULL, типски конфликт).

Ако редовно пратиш ове две вредности, рано ћеш открити да ли се нешто променило на извору (нпр. нови формат) или да ли је циљни систем постао строгрији (нпр. нови constraints).

Закључавања и прозори оптерећења

Bulk-INSERT-ови могу изазвати закључавања и IO оптерећење. Ако корисници паралелно раде на истим табелама, мораш размотрити isolation level, индексе и евентуално партиционисање. Практично то значи: или сместити импорте у прозоре с мањим оптерећењем, или пројектовати ток података тако да коегзистира са радним системом (нпр. преко Staging-а + асинхроног преузимања).

Конкретна чек-листа за робустан Bulk-INSERT са Array DML

  • Величина батча одредити (почетна вредност 500–1.000) и мерљиво подесити.
  • Експлицитна транзакција: commit по батчу као подразумевано, „commit на крају“ само свесно.
  • Поставити стабилне типове параметара, не приморавати имплицитне кастове.
  • Контекст грешке по запису водити (спољашњи ID, ред извора).
  • Стратегија за грешке: прво батч, затим split/fallback, логовати по реду.
  • Логовање: кодови + текст, али у складу са заштитом података; евидентирати Batch-ID и Lauf-ID.
  • Повратно покретање: обезбедити идемпотентност (кључ/Upsert/Import-ID).

Закључак: Array DML је брз – робустан постаје захваљујући процесу и стратегији за грешке

Jedan FireDAC Bulk-Insert sa Array DML je snažan alat, sve dok se ne praviš da grešaka nema. U stvarnim tokovima podataka uvek ima odstupanja: duplikati, nedostajuće reference, neispravne vrednosti datuma. Zato je čist pristup: Array DML za performanse, kombinovan sa kontrolisanom strategijom izolacije (Split ili Fallback) i listom grešaka koja se može pratiti po redu. Tako dobijaš brzinu i operativnu sigurnost zajedno – i upravo to je bitno kada importi ne trče samo u laboratoriji, već moraju svake noći pouzdano proći.

Ako želite stabilizovati postojeći proces uvoza ili interfejsa u Delphi/FireDAC (performanse, transakcije, ponovno pokretanje, logovanje), razjasnićemo to rado strukturirano u tehničkom razgovoru:

Za ovu temu su takođe važni Delphi Bulk Insert i Bulk Insert Delphi FireDAC. Članak ove aspekte jasno razlaže i pokazuje na šta u praksi treba obratiti pažnju.

Razgovarajte o projektu ili modernizacionom poduhvatu sa Net-Base.

Следећи корак

Када из теме настане реалан пројекат, архитектуру, постојеће стање и операције треба рано разматрати заједно.

Подржавамо не само у појединачним питањима, већ и када из исечака изворног кода, застарелих тема или идеја за портале треба да настане поуздан корпоративни пројекат.

  • Постојеће стање, циљано стање и технички ризици оцењују се заједно.
  • REST, приступ подацима, портали и увођење неће бити одложени за касније фазе.
  • Ви рано увидите који пут је економски и оперативно одржив.

Подели објаву

Поделите ову објаву директно

LinkedIn, X, XING, Facebook, WhatsApp и е-пошта су одмах доступни. За Instagram одмах припремамо линк и кратак текст.

Е-пошта

Инстаграм се отвара у новој картици. Линк и кратак текст се претходно копирају у међуспремник.