by WebSurfer
15. September 2022 19:24
SQL Server の Multiple Active Result Sets (MARS) というのは何で、どのような場合に必要かという話を書きます。
MARS は SQL Server 2005 以降で利用できる機能で、Microsoft のドキュメント「複数のアクティブな結果セットの有効化」によると "複数のバッチを単一の接続で実行することができます" ということです。(分かりやすい説明を下の方に追記)
接続文字列で MultipleActiveResultSets を true に設定することにより利用できます。
.NET Framework 2.0 からサポートされていたのですが、昔はそのような設定を見かけることは無かったです。それが ADO.NET Entity Data Model ウィザードで自動生成される接続文字列などに設定されるのを見かけて、なぜだろうと疑問に思っていました。
接続文字列で MultipleActiveResultSets=True として「複数のアクティブな結果セットの有効化」を行った例を以下に書きます。
string connString1 = "Data Source=lpc:(local)\\sqlexpress;" +
"Initial Catalog=NORTHWIND;" +
"Integrated Security=True;" +
"MultipleActiveResultSets=True";
string query1 = "SELECT CategoryID, CategoryName FROM Categories;";
string query2 = "SELECT ProductID, ProductName FROM Products;";
using (var connection = new SqlConnection(connString1))
{
connection.Open();
using (var command = new SqlCommand(query1, connection))
{
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("\t{0}\t{1}",
reader.GetInt32(0), reader.GetString(1));
}
}
using (var command = new SqlCommand(query2, connection))
{
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("\t{0}\t{1}",
reader.GetInt32(0), reader.GetString(1));
}
}
}
MARS はデフォルトでは無効になっており、その場合はアプリケーションはバッチごとにすべての結果セットを処理またはキャンセルしないと、同じ接続で他のバッチを実行できません。
どういうことかと言うと、接続文字列の MultipleActiveResultSets=True を削除すると 2 つ目の command.ExecuteReader() で以下のように例外がスローされます。

上のコードでは、MARS の設定なしでも、DataReader を閉じるコードを書けば例外は回避できるのですが、Entity Framework が問題です。
例えば、Entity Framework の「遅延読み込み」を行ったりすると、MARS の設定無しでは以下の画像のように例外がスローされます。

ADO.NET Entity Data Model ウィザードなどで自動生成される接続文字列に MARS の設定が含まれているのはそういう理由であろうと思われます。
2022/9/28 追記
MSDN ライブラリ Visual Studio 2008 の SqlCommand.ExecuteReader メソッドの解説に MARS の分かりやすい説明があるのを見つけましたので以下に書いておきます。
"SQL Server 2005 より前のバージョンの SQL Server の場合、SqlDataReader が使用されている間、関連付けられている SqlConnection は SqlDataReader によって使用されるため、ビジー状態になります。この状態では、SqlConnection に対して、閉じる以外の操作を実行できません。SqlDataReader の Close メソッドを呼び出すまでこの状態が続きます。SQL Server 2005 では、MARS (Multiple Active Result Set) 機能がサポートされ、同一接続を使用して複数の処理を実行できるようになりました"