C#、.NET、SQL Server における "MultipleActiveResultSets=True" と 複数の接続
C#、.NET、SQL Server を使用する場合、複数のクエリを同時に実行し、結果セットを個別に処理したいことがあります。これを実現するには、2 つの方法があります。
- MultipleActiveResultSets (MARS) を有効にする
- 複数の接続を使用する
MARS
MARS は、単一の接続で複数のクエリを同時に実行し、結果セットを個別に処理できる機能です。これは、接続あたりのクエリ数を減らし、パフォーマンスを向上させるのに役立ちます。
MARS を有効にする方法
- 接続文字列
接続文字列に MultipleActiveResultSets=True
オプションを追加します。
var connectionString = "Data Source=localhost;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True";
- SqlConnectionStringBuilder
SqlConnectionStringBuilder
クラスを使用して、接続文字列を構築し、MultipleActiveResultSets
プロパティを True
に設定します。
var connectionStringBuilder = new SqlConnectionStringBuilder();
connectionStringBuilder.DataSource = "localhost";
connectionStringBuilder.InitialCatalog = "Test";
connectionStringBuilder.IntegratedSecurity = true;
connectionStringBuilder.MultipleActiveResultSets = true;
var connectionString = connectionStringBuilder.ConnectionString;
複数の接続
MARS を使用せずに複数のクエリを同時に実行するには、複数の接続を作成できます。
var connection1 = new SqlConnection("Data Source=localhost;Initial Catalog=Test;Integrated Security=True");
var connection2 = new SqlConnection("Data Source=localhost;Initial Catalog=Test;Integrated Security=True");
// クエリを実行
var command1 = new SqlCommand("SELECT * FROM Table1", connection1);
var command2 = new SqlCommand("SELECT * FROM Table2", connection2);
var reader1 = command1.ExecuteReader();
var reader2 = command2.ExecuteReader();
// 結果セットを処理
while (reader1.Read())
{
// ...
}
while (reader2.Read())
{
// ...
}
// 接続を閉じる
connection1.Close();
connection2.Close();
どちらの方法を選択するべきか
どちらの方法を選択するかは、パフォーマンス要件とアプリケーションのアーキテクチャによって異なります。
- パフォーマンス
MARS は、複数の接続を使用するよりもパフォーマンスが優れている場合があります。これは、接続あたりのオーバーヘッドが少なくなるためです。
- アプリケーションアーキテクチャ
複数の接続を使用する方が、アプリケーションアーキテクチャをシンプルに保つことができる場合があります。これは、各接続が独立した操作を実行するためです。
注意事項
- MARS は、SQL Server 2005 以降で使用できます。
- MARS を使用するには、データベースが MARS に対応している必要があります。
- MARS を使用すると、接続プーリングの動作が変わる場合があります。
using System;
using System.Data.SqlClient;
namespace MultipleActiveResultSetsSample
{
class Program
{
static void Main(string[] args)
{
// 接続文字列
var connectionString = "Data Source=localhost;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True";
// 接続を開く
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
// 1 つ目のクエリを実行
var command1 = new SqlCommand("SELECT * FROM Table1", connection);
var reader1 = command1.ExecuteReader();
// 2 つ目のクエリを実行
var command2 = new SqlCommand("SELECT * FROM Table2", connection);
var reader2 = command2.ExecuteReader();
// 結果セットを処理
while (reader1.Read())
{
// ...
}
while (reader2.Read())
{
// ...
}
// 接続を閉じる
connection.Close();
}
}
}
}
using System;
using System.Data.SqlClient;
namespace MultipleConnectionsSample
{
class Program
{
static void Main(string[] args)
{
// 接続文字列
var connectionString = "Data Source=localhost;Initial Catalog=Test;Integrated Security=True";
// 1 つ目の接続を開く
using (var connection1 = new SqlConnection(connectionString))
{
connection1.Open();
// 1 つ目のクエリを実行
var command1 = new SqlCommand("SELECT * FROM Table1", connection1);
var reader1 = command1.ExecuteReader();
// 2 つ目の接続を開く
using (var connection2 = new SqlConnection(connectionString))
{
connection2.Open();
// 2 つ目のクエリを実行
var command2 = new SqlCommand("SELECT * FROM Table2", connection2);
var reader2 = command2.ExecuteReader();
// 結果セットを処理
while (reader1.Read())
{
// ...
}
while (reader2.Read())
{
// ...
}
// 2 つ目の接続を閉じる
connection2.Close();
}
// 1 つ目の接続を閉じる
connection1.Close();
}
}
}
}
実行方法
- Visual Studio で新しい C# コンソールアプリケーションプロジェクトを作成します。
- 接続文字列を自分の環境に合わせて変更します。
- プロジェクトをビルドして実行します。
MARS と複数の接続以外の方法
SqlDataReader
クラスの NextResult()
メソッドを使用して、複数の結果セットを順番に処理することができます。
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var command = new SqlCommand("SELECT * FROM Table1; SELECT * FROM Table2", connection);
var reader = command.ExecuteReader();
while (reader.Read())
{
// Table1 の処理
}
if (reader.NextResult())
{
while (reader.Read())
{
// Table2 の処理
}
}
connection.Close();
}
SqlCommand オブジェクトの BatchSize プロパティを使用する
SqlCommand
クラスの BatchSize
プロパティを使用して、複数のクエリを 1 つのバッチとして送信することができます。
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var command = new SqlCommand();
command.Connection = connection;
command.BatchSize = 2;
command.CommandText = "SELECT * FROM Table1";
command.ExecuteNonQuery();
command.CommandText = "SELECT * FROM Table2";
command.ExecuteNonQuery();
connection.Close();
}
ストアドプロシージャを使用する
CREATE PROCEDURE dbo.GetTables
AS
BEGIN
SELECT * FROM Table1;
SELECT * FROM Table2;
END
GO
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var command = new SqlCommand("dbo.GetTables", connection);
var reader = command.ExecuteReader();
while (reader.Read())
{
// Table1 または Table2 の処理
}
connection.Close();
}
- これらの方法は、MARS や複数の接続を使用するよりもパフォーマンスが劣る場合があります。
- これらの方法は、すべての状況で使えるわけではありません。
c# .net sql-server