SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

SQLの挿入処理の高速化

複数行挿入によるデータベースのパフォーマンス向上

挿入の比較

 テーブルにデータを挿入するには、さまざまな方法があります。ANSI準拠の方法もあれば、RDBMS固有の方法もあります。しかしどの方法も、1行の挿入か、または複数行の挿入です。言うまでもなく、複数行の挿入の方が1行の挿入を繰り返すよりずっと高速ですが、では、どの程度高速なのでしょうか。この疑問を解決すべく、リスト1のテストを実行します。

リスト1 1行挿入と複数行挿入の比較に使用するバッチスクリプト
/*-----------------------------------------------------------------
 Batch 1
 Create and populate table testInserts
------------------------------------------------------------------
*/
IF EXISTS (SELECT * FROM sysobjects
             WHERE id = OBJECT_ID('testInserts') AND type in ('U'))
DROP TABLE testInserts;
GO
SET NOCOUNT ON;
CREATE TABLE testInserts(
   insID int IDENTITY(1,1) NOT NULL,
   OrderID int NOT NULL);
INSERT INTO testInserts(OrderID)
SELECT OrderID FROM Northwind..Orders;
DECLARE @i as int, @LoopMax int, @MaxID int;
SELECT  @i = 1, @LoopMax = 2, @MaxID = 0;
WHILE (@i <= @LoopMax)
BEGIN
   INSERT INTO testInserts(OrderID)
   SELECT OrderID + @MaxID FROM testInserts;
   SELECT @MaxID = MAX(OrderID) FROM testInserts;
   SELECT @i = @i + 1;
END;
GO
/*-----------------------------------------------------------------
 Batch 2
 Test many-rows insert
------------------------------------------------------------------
*/
IF EXISTS (SELECT * FROM sysobjects
             WHERE id = OBJECT_ID('t1') AND type IN ('U'))
DROP TABLE t1;
GO
CREATE TABLE t1(
   c1 int NOT NULL,
   c2 int NOT NULL);
INSERT INTO t1
SELECT insID, OrderID FROM testInserts;
GO
/*-----------------------------------------------------------------
 Batch 3
 Test one-row inserts
------------------------------------------------------------------
*/
IF EXISTS (SELECT * FROM sysobjects
             WHERE id = OBJECT_ID('t2') AND type IN ('U'))
DROP TABLE t2;
GO
CREATE TABLE t2(
   c1 int NOT NULL,
   c2 int NOT NULL);
-- Generate INSERT statements
SELECT 'INSERT INTO t2 VALUES(' + CAST(insID AS VARCHAR(15)) + ','
   + CAST(OrderID AS VARCHAR(15))  + ');' + CHAR(10) + 'GO'
FROM testInserts;

-- Result:
INSERT INTO t2 VALUES(1,10249);
GO
INSERT INTO t2 VALUES(2,10251);
GO
. . . . . . . . . . . . . . . .

INSERT INTO t2 VALUES(3320,44292);
GO
(3320 row(s) affected)

 リスト1のすべてのバッチを個別に実行します。バッチ1は、テーブル「testInserts」を作成して、データを読み込みます。最初のINSERT(ループの前)では、テーブル「Northwind..Orders」からOrderIDを選択して、830行を読み込みます(SQL Server 2005(SS2005)を使用していて、Northwindデータベースをインストールしていない場合は、Microsoftダウンロードセンターからこれをダウンロードできます)。次に、各ループの反復によって、テーブル「testInserts」の行数が2倍になります。2回の反復によって、行数は最終的に3,320になります。

 1行挿入をテストするには、バッチ3の結果をクエリアナライザまたはManagement Studioの新しいウィンドウにコピーして、実行します。さまざまなハードウェア構成のいくつかのマシンで試したところ、複数行挿入(バッチ2)の実行時間は約46ミリ秒でしたが、1行挿入(バッチ3)の実行時間は約36ミリ秒でした(SS2000関連での実行結果)。つまり、複数行挿入の方が、1行挿入を繰り返すよりも数倍高速です。

 1行挿入の繰り返しは、さまざまな要因で低速になります。例えば、反復的な1行挿入の場合は、膨大な数のロックや実行プランが必要になりますし、SQL Serverが発行する実行文もかなりの数に上ります。また、個々の挿入操作(バッチ)で、オブジェクトのアクセス許可の取得、BEGINトランザクションとCOMMITトランザクション、トランザクションログへのデータの書き込みが必要です(単純なリカバリモデルの場合でも同様です)。

 プロファイラを使って挿入をトレースした結果の一部を、以下に示します。

1行挿入複数行挿入
BEGIN...COMMITトランザクションのペア7,2651
トランザクションログへの書き込み11,0456,360
ロック26,98611,670

 SQL Serverは、新しい行の領域を見つけるメカニズムがやや複雑であることにも注意してください。リスト1に示すように、ヒープテーブルの場合、SQL ServerはIAM(Index Allocation Map)ページとPFS(Page Free Space)ページを使って、テーブルに既に割り当てられているページの中から、空き領域を持つデータページを見つけます。すべてのページが埋まっている場合は、GAM(Global Allocation Map)とSGAM(Shared Global Allocation Map)を使って、混合エクステント内で空きページを見つけるか、新しい均一エクステントをテーブルに割り当てることを試みます。リスト1の例は、ヒープテーブルであり削除は行わないので、テーブルに割り当てられている最終ページの末尾にデータが挿入されます。そのため、マルチユーザー環境や、複数のアプリケーションサーバーが1つのデータベースを使用している場合は、テーブルの末尾に「ホットスポット」が生じる可能性があります。

 反復的な1行挿入の場合、SQL Serverは、挿入の数だけ割り当てメカニズムを起動します。複数行挿入の場合は、すべての挿入行を扱えるだけの領域が即時に割り当てられます。インデックス付きのテーブルの場合は、クラスタ化インデックスに合わせてデータページを分割したり、非クラスタ化インデックスに合わせてインデックス更新を行うことができます。

次のページ
挿入を高速化する方法

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Alex Kozak(Alex Kozak)

SAP Canadaの上級DBA/アナリスト。データベースとプログラミングに15年以上従事。MSDNライブラリにも多数投稿。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/390 2006/08/22 15:47

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー