sql >> データベース >  >> RDS >> Sqlserver

SQL Server一括挿入–パート2

    この記事の前の部分では、BULKINSERTステートメントを使用してCSVファイルをSQLServerにインポートする方法について説明しました。一括挿入プロセスの主な方法論と、シナリオでのBATCHSIZEおよびMAXERRORSオプションの詳細についても説明しました。このパートでは、さまざまなシナリオでの一括挿入プロセスの他のオプション(FIRE_TRIGGERS、CHECK_CONSTRAINTS、およびTABLOCK)について説明します。

    シナリオ1:一括挿入操作中に宛先テーブルでトリガーを有効にできますか?

    デフォルトでは、一括挿入プロセス中に、ターゲットテーブルで指定された挿入トリガーは起動されませんが、状況によっては、これらのトリガーを有効にしたい場合があります。この問題の解決策は、一括挿入ステートメントでFIRE_TRIGGERSオプションを使用することです。トリガー/トリガーはデータベースで個別の操作を行うことができるため、このオプションが一括挿入操作のパフォーマンスに影響を与え、低下させる可能性があることに注意してください。次のサンプルでは、​​これを示します。最初は、FIRE_TRIGGERSパラメーターを設定せず、一括挿入プロセスは挿入トリガーを起動しません。次のT-SQLスクリプトでは、Salesテーブルの挿入トリガーを定義します。

    DROP TABLE IF EXISTS Sales 
    
    CREATE TABLE [dbo].[Sales](
    	[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 SalesLog
    CREATE TABLE SalesLog (OrderIDLog bigint)
    GO
    CREATE TRIGGER OrderLogIns ON Sales
    FOR INSERT
    AS
    BEGIN 
    SET NOCOUNT ON 
    INSERT INTO SalesLog
    SELECT OrderId from inserted
    end
    
    GO
    BULK INSERT Sales
    FROM 'C:\1500000 Sales Records.csv'
    WITH (FIRSTROW = 2,
        FIELDTERMINATOR = ',',
    	ROWTERMINATOR='\n'
    	 );
    
    
    	SELECT Count(*) FROM SalesLog
    

    上記のように、FIRE_TRIGGERSオプションを設定しなかったため、挿入トリガーは起動しませんでした。次に、FIRE_TRIGGERSオプションを一括挿入ステートメントに追加して、このオプションで起動トリガーを挿入できるようにします。

    BULK INSERT Sales
    FROM 'C:\1500000 Sales Records.csv'
    WITH (FIRSTROW = 2, 
    FIELDTERMINATOR = ',', 
    ROWTERMINATOR='\n',
    FIRE_TRIGGERS);
    GO
    SELECT Count(*) as [NumberOfRowsinTriggerTable] FROM SalesLog 
    
    

    シナリオ2:一括挿入操作中にチェック制約を有効にするにはどうすればよいですか?

    チェック制約を使用すると、SQLServerテーブルでデータの整合性を強化できます。制約の目的は、構文規則に従って、挿入、更新、または削除された値をチェックすることです。たとえば、NOT NULL制約は、指定された列をNULL値で変更できないことを規定しています。次に、制約と一括挿入の相互作用に焦点を当てます。デフォルトでは、一括挿入プロセス中、チェックと外部キーの制約は無視されますが、このオプションにはいくつかの例外があります。 Microsoftのドキュメントによると、「UNIQUEおよびPRIMARYKEY制約は常に適用されます。 NOT NULL制約が定義されている文字列にインポートする場合、テキストファイルに値がない場合、BULKINSERTは空白の文字列を挿入します。」 次のT-SQLスクリプトでは、2016年1月1日より後の注文日を制御するCheck制約をOrderDate列に追加します。

    DROP TABLE IF EXISTS Sales 
    
    CREATE TABLE [dbo].[Sales](
    	[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_Check
    CHECK(OrderDate >'20160101')
    
    BULK INSERT Sales
    FROM 'C:\1500000 Sales Records.csv'
    WITH (FIRSTROW = 2,
        FIELDTERMINATOR = ',',
    	ROWTERMINATOR='\n'
    	 );
    GO
    SELECT COUNT(*) AS [UnChekedData] FROM 
    Sales WHERE OrderDate <'20160101'
    

    上記のサンプルでわかるように、一括挿入プロセスはチェック制約制御をスキップします。ただし、SQL Serverは、チェック制約を信頼できないものとして示しています。

    SELECT is_not_trusted ,* FROM sys.check_constraints where name='OrderDate_Check'

    この値は、チェック制約をスキップすることにより、誰かがこの列にデータを挿入または更新したことを示します。同時に、この列には、その制約に関して一貫性のないデータが含まれている可能性があります。次に、CHECK_CONSTRAINTSオプションを使用して一括挿入ステートメントを実行してみます。結果は非常に単純です。データが不適切なため、チェック制約はエラーを返します。

    BULK INSERT Sales
    FROM 'C:\1500000 Sales Records.csv'
    WITH (FIRSTROW = 2,
        FIELDTERMINATOR = ',',
    	ROWTERMINATOR='\n'
    	 );
    

    シナリオ3:1つの宛先テーブルへの複数の一括挿入のパフォーマンスを向上させる方法

    SQL Serverのロックメカニズムの主な目的は、データの整合性を保護および保証することです。 SQL Serverのロックの主な概念に関する記事で、ロックメカニズムの詳細を確認できます。次に、一括挿入プロセスのロックの詳細に焦点を当てます。 TABLELOCKオプションを指定せずに一括挿入ステートメントを実行すると、ロック階層に従って行またはテーブルのロックが取得されます。ただし、場合によっては、1つの宛先テーブルに対して複数の一括挿入プロセスを実行して、一括挿入の操作時間を短縮できるようにすることができます。最初に、2つの一括挿入ステートメントを同時に実行し、ロックメカニズムの動作を分析します。 SQL Server Management Studioで2つのクエリウィンドウを開き、次の一括挿入ステートメントを同時に実行します。

    BULK INSERT Sales
    FROM 'C:\1500000 Sales Records.csv'
    WITH (FIRSTROW = 2,
        FIELDTERMINATOR = ',',
    	ROWTERMINATOR='\n'
    	 );
    

    次のdmv(動的管理ビュー)クエリを実行すると、一括挿入プロセスのステータスを監視するのに役立ちます。

    SELECT session_id,command ,status,last_wait_type,text FROM sys.dm_exec_requests cross apply 
    sys.dm_exec_sql_text(sys.dm_exec_requests.sql_handle)
    where text like '%BULK INSERT Sales%' and session_id <>@@SPID
    

    上の画像のセッション61でわかるように、一括挿入プロセスのステータスはロックのために一時停止されています。問題を確認すると、セッション59は一括挿入先テーブルをロックし、セッション61はこのロックが解除されるのを待って一括挿入プロセスを続行します。次に、TABLOCKオプションを一括挿入ステートメントに追加し、クエリを実行します。

    dmv監視クエリを再度実行すると、SQL Serverがバルク更新ロック(BU)と呼ばれる特別なロックタイプを使用しているため、中断されたバルク挿入プロセスを確認できません。このロックタイプを使用すると、同じテーブルに対して複数の一括挿入操作を同時に処理できます。また、このオプションを使用すると、一括挿入プロセスの合計時間が短縮されます。

    一括挿入プロセス中に次のクエリを実行すると、ロックの詳細とロックの種類を監視できます。

    SELECT dm_tran_locks.request_session_id,
           dm_tran_locks.resource_database_id,
           DB_NAME(dm_tran_locks.resource_database_id) AS dbname,
           CASE
               WHEN resource_type = 'OBJECT'
                   THEN OBJECT_NAME(dm_tran_locks.resource_associated_entity_id)
               ELSE OBJECT_NAME(partitions.OBJECT_ID)
           END AS ObjectName,
           partitions.index_id,
           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_status
    FROM sys.dm_tran_locks
    LEFT JOIN sys.partitions ON partitions.hobt_id = dm_tran_locks.resource_associated_entity_id
    LEFT JOIN sys.indexes ON indexes.OBJECT_ID = partitions.OBJECT_ID AND indexes.index_id = partitions.index_id
    WHERE resource_associated_entity_id > 0
      AND resource_database_id = DB_ID()
    

    結論

    この記事では、SQLServerでの一括挿入操作のすべての詳細について説明しました。特に、BULK INSERTコマンドとその設定およびオプションについて説明し、実際の問題に近いさまざまなシナリオも分析しました。

    参照

    一括挿入(Transact-SQL)

    一括インポートでの最小限のロギングの前提条件

    一括インポートのロック動作の制御

    参考資料

    BCPユーティリティを使用したフラットファイルへのデータのエクスポートと一括挿入を使用したデータのインポート

    便利なツール:

    dbForge Data Pump – SQLデータベースに外部ソースデータを入力し、システム間でデータを移行するためのSSMSアドイン。


    1. SQLのSUBSTRINGコマンド:入門書

    2. INNER JOIN ONvsWHERE句

    3. SQL Serverトリガーは、新しい行から別のテーブルに値を挿入します

    4. OPENJSONを使用してSQLServerでネストされたJSONを選択する方法