V předchozí části tohoto článku jsme diskutovali o tom, jak importovat soubory CSV na SQL Server pomocí příkazu BULK INSERT. Probrali jsme hlavní metodologii procesu hromadného vkládání a také podrobnosti o možnostech BATCHSIZE a MAXERRORS ve scénářích. V této části si projdeme některé další možnosti (FIRE_TRIGGERS, CHECK_CONSTRAINTS a TABLOCK) procesu hromadného vkládání v různých scénářích.
Scénář 1:Můžeme povolit spouštěče v cílové tabulce během operace hromadného vkládání?
Ve výchozím nastavení se během procesu hromadného vkládání nespouštějí spouštěče vložení, které jsou uvedeny v cílové tabulce, v některých situacích však můžeme chtít tyto spouštěče povolit. Řešením tohoto problému je použití možnosti FIRE_TRIGGERS v příkazech hromadného vložení. Chci přidat upozornění, že tato možnost může ovlivnit a snížit výkon operace hromadného vkládání, protože spouštěče/spouštěče mohou provádět samostatné operace v databázi. V následující ukázce si to ukážeme. Nejprve nenastavíme parametr FIRE_TRIGGERS a proces hromadného vložení nespustí trigger vložení. V následujícím skriptu T-SQL definujeme spouštěč vložení pro tabulku Prodej.
DROP TABLE IF EXISTS Sales CREATE TABLE [dbo].[Prodej]( [Region] [varchar](50) , [Country] [varchar](50) , [ItemType] [varchar](50) NULL, [ SalesChannel] [varchar](50) NULL, [OrderPriority] [varchar](50) NULL, [OrderDate] datetime, [OrderID] bigint NULL, [ShipDate] datetime, [UnitsSold] float, [UnitPrice] float, [UnitCost] float, [TotalRevenue] float, [TotalCost] float, [TotalProfit] float) DROP TABLE IF EXISTS SalesLogCREATE TABLE SalesLog (OrderIDLog bigint)GOCREATE TRIGGER OrderLogIns ON SalesFOR INSERTASBEGIN SET NOCOUNT ON INSERT INTO Insertd0LKNSSELECT1S SalesdSELECT15ROM Sales Sales Records.csv'WITH (FIRSTROW =2, FIELDTERMINATOR =',', ROWTERMINATOR='\n' ); SELECT Count(*) FROM SalesLog
Jak můžete vidět výše, trigger vložení se nespustil, protože jsme nenastavili možnost FIRE_TRIGGERS. Nyní do příkazu hromadného vložení přidáme možnost FIRE_TRIGGERS, aby tato možnost umožnila vložit spouštěč.
BULK INSERT SalesFROM 'C:\1500000 Sales Records.csv'WITH (FIRSTROW =2, FIELDTERMINATOR =',', ROWTERMINATOR='\n',FIRE_TRIGGERS);GOSELECT Count(*) jako [NumberOfRowsinTriggerTiggerTable] /před>
Scénář 2:Jak lze povolit kontrolní omezení během operace hromadného vkládání?
Kontrolní omezení nám umožňují vynutit integritu dat v tabulkách SQL Server. Účelem omezení je zkontrolovat vložené, aktualizované nebo vymazané hodnoty podle jejich syntaxe. Například omezení NOT NULL zajišťuje, že zadaný sloupec nemůže být upraven hodnotou NULL. Nyní se zaměříme na omezení a interakci hromadného vložení. Ve výchozím nastavení jsou během procesu hromadného vkládání všechna omezení kontroly a cizího klíče ignorována, ale tato možnost má některé výjimky. Podle dokumentace společnosti Microsoft „Vždy jsou vynucována omezení UNIQUE a PRIMARY KEY. Při importu do sloupce znaků, pro který je definováno omezení NOT NULL, vloží BULK INSERT prázdný řetězec, pokud v textovém souboru není žádná hodnota.“ V následujícím skriptu T-SQL přidáme do sloupce Datum objednávky kontrolní omezení, které řídí datum objednávky větší než 01.01.2016.
DROP TABLE IF EXISTS Sales CREATE TABLE [dbo].[Prodej]( [Region] [varchar](50) , [Country] [varchar](50) , [ItemType] [varchar](50) NULL, [ SalesChannel] [varchar](50) NULL, [OrderPriority] [varchar](50) NULL, [OrderDate] datetime, [OrderID] bigint NULL, [ShipDate] datetime, [UnitsSold] float, [UnitPrice] float, [UnitCost] float, [TotalRevenue] float, [TotalCost] float, [TotalProfit] float) ALTER TABLE [Sales] ADD CONSTRAINT OrderDate_CheckCHECK(OrderDate>'20160101')HROMADNÉ INSERT SalesFROM 'C:\1500000 Sales Records (2WITHO00 Sales Records.cs , FIELDTERMINATOR =',', ROWTERMINATOR='\n' );GOSELECT COUNT(*) AS [UnChekedData] FROM Sales WHERE OrderDate <'20160101'
Jak můžete vidět na výše uvedené ukázce, proces hromadného vkládání přeskočí kontrolu omezení kontroly. SQL Server však označuje kontrolní omezení jako nedůvěryhodné.
SELECT is_not_trusted ,* FROM sys.check_constraints where name='OrderDate_Check'
Tato hodnota označuje, že někdo vložil nebo aktualizoval některá data do tohoto sloupce přeskočením kontrolního omezení, zároveň může tento sloupec obsahovat nekonzistentní data s odkazem na toto omezení. Nyní se pokusíme provést příkaz hromadného vložení s možností CHECK_CONSTRAINTS. Výsledek je velmi jednoduchý, kontrolní omezení vrací chybu kvůli nesprávným datům.
BULK INSERT SalesFROM 'C:\1500000 Sales Records.csv'WITH (FIRSTROW =2, FIELDTERMINATOR =',', ROWTERMINATOR='\n');
Scénář 3:Jak zvýšit výkon více hromadných vkládání do jedné cílové tabulky?
Hlavním účelem zamykacího mechanismu v SQL Server je ochrana a zajištění integrity dat. Podrobnosti o zamykacím mechanismu naleznete v článku Hlavní koncepce zamykání serveru SQL Server. Nyní se zaměříme na podrobnosti zamykání procesu hromadného vkládání. Pokud spustíte příkaz hromadného vložení bez možnosti TABLELOCK, získá zámek řádků nebo tabulky podle hierarchie zámku. V některých případech však můžeme chtít provést více procesů hromadného vkládání u jedné cílové tabulky, takže můžeme zkrátit dobu provozu hromadného vkládání. Nejprve provedeme dva příkazy hromadného vložení současně a analyzujeme chování zamykacího mechanismu. Otevřeme dvě okna dotazů v SQL Server Management Studio a současně spustíme následující příkazy hromadného vložení.
BULK INSERT SalesFROM 'C:\1500000 Sales Records.csv'WITH (FIRSTROW =2, FIELDTERMINATOR =',', ROWTERMINATOR='\n');
Když spustíme následující dotaz dmv (Dynamic Management View), který pomáhá sledovat stav procesu hromadného vkládání.
SELECT session_id,command ,status,last_wait_type,text FROM sys.dm_exec_requests cross použít sys.dm_exec_sql_text(sys.dm_exec_requests.sql_handle) kde text jako '%BULK INSERT Sales%' a session_id>@@SPID <>@@SP
Jak můžete vidět na obrázku výše, relace 61, stav procesu hromadného vkládání je pozastaven kvůli uzamčení. Pokud problém ověříme, relace 59 uzamkne cílovou tabulku hromadného vkládání a relace 61 čeká na uvolnění tohoto zámku, aby proces hromadného vkládání pokračoval. Nyní do příkazů hromadného vložení přidáme možnost TABLOCK a spustíme dotazy.
Když znovu spustíme dotaz monitorování dmv, nevidíme žádný pozastavený proces hromadného vkládání, protože SQL Server používá speciální typ zámku nazvaný zámek hromadné aktualizace (BU). Tento typ zámku umožňuje zpracovávat více operací hromadného vkládání proti stejné tabulce současně a tato možnost také zkracuje celkovou dobu procesu hromadného vkládání.
Když během procesu hromadného vkládání provedeme následující dotaz, můžeme sledovat podrobnosti zamykání a typy zámků.
SELECT dm_tran_locks.request_session_id, dm_tran_locks.resource_database_id, DB_NAME(dm_tran_locks.resource_database_id) AS název_databáze, CASE WHEN resource_type ='OBJECT' THEN OBJECT_NAME(dm_tran_locks_OBJECT_NAME) index_objektu_objektu. indexes.name AS index_name, dm_tran_locks.resource_type, dm_tran_locks.resource_description, dm_tran_locks.resource_associated_entity_id, dm_tran_locks.request_mode, dm_tran_locks.request_statusFROM sys.dm_tran_locksLEFT JOIN sys.partitions ON partitions.hobt_id =dm_tran_locks.resource_associated_entity_idLEFT JOIN sys.indexes ON indexes.OBJECT_ID =partitions .OBJECT_ID AND indexes.index_id =partitions.index_idWHERE resource_associated_entity_id> 0 AND resource_database_id =DB_ID()
Závěr
V tomto článku jsme prozkoumali všechny podrobnosti operace hromadného vkládání na SQL Server. Konkrétně jsme zmínili příkaz BULK INSERT a jeho nastavení a možnosti a také jsme analyzovali různé scénáře, které se blíží skutečným problémům.
Odkazy
HROMADNÉ VLOŽENÍ (Transact-SQL)
Předpoklady pro minimální přihlášení při hromadném importu
Řízení zamykacího chování pro hromadný import
Další čtení
Export dat do plochého souboru pomocí nástroje BCP a import dat pomocí hromadného vkládání
Užitečný nástroj:
dbForge Data Pump – doplněk SSMS pro plnění databází SQL externími zdrojovými daty a migraci dat mezi systémy.