SqlClient の AppContext 切り替え

適用対象: .NET Framework .NET .NET Standard

ADO.NET のダウンロード

AppContext クラスを使用すれば、SqlClient によって、以前の動作に依存する呼び出し元を引き続きサポートしながら、新しい機能を提供することができます。 ユーザーは、特定の AppContext スイッチを設定することによって、動作の変更をオプトアウトすることができます。

SqlClientは各スイッチを初めて使用した際に読み取りとキャッシュを行います。 アプリケーション起動時にスイッチを設定し、SqlClientタイプを使う前に設定してください。 SqlClientが値をキャッシュした後にスイッチを変更しても影響はありません。

MultiSubnetFailover を既定で有効にする

適用対象: .NET Framework、.NET、.NET Standard

(バージョン 7.0 以降で使用可能)

個々の接続文字列を変更せずにグローバルに MultiSubnetFailover=true を設定するには、アプリケーション起動時にAppContextスイッチ Switch.Microsoft.Data.SqlClient.EnableMultiSubnetFailoverByDefault を true に設定してください:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.EnableMultiSubnetFailoverByDefault", true);

App.Config でこのスイッチを有効にすることもできます。

<runtime>
  <AppContextSwitchOverrides value="Switch.Microsoft.Data.SqlClient.EnableMultiSubnetFailoverByDefault=true" />
</runtime>

有効にすると、すべての接続は接続文字列に MultiSubnetFailover=true が設定されているかのように動作します。 このスイッチは既定で無効になっています。

非同期読み取りのパケット多重化を有効にする

適用対象: .NET Framework、.NET、.NET Standard

(バージョン 7.0 以降で使用可能)

パケット多重化により、大きな結果セットを使用した ExecuteReaderAsync 、ストリーミング シナリオ、一括データ取得などの大規模な非同期読み取り操作のパフォーマンスが向上します。 この機能は、2 つのオプトイン AppContext スイッチによって制御されます。 両方のスイッチを false に設定すると、新しい非同期処理パスが有効になります。

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseCompatibilityAsyncBehaviour", false);
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseCompatibilityProcessSni", false);

既定では、両方のスイッチが trueされ、既存の (互換性のある) 動作が保持されます。

10 進数の切り捨て動作を有効にする

適用対象: .NET Framework、.NET、.NET Standard

Microsoft.Data.SqlClient 2.0 以降、SQL Server と同様に、10 進データはデフォルトで四捨五入されます。 以前の切断動作を有効にするには、アプリケーション起動時にAppContextスイッチ Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal を true に設定できます:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal", true);

Windows でマネージド ネットワークを有効にする

適用対象: .NET、.NET Standard

(バージョン 2.0 以降で使用できます)

Windows 上の SqlClient では既定では SNI ネットワーク インターフェイスのネイティブ実装が使用されます。 マネージドSNI実装の使用を有効にするには、アプリケーション起動時にAppContextスイッチSwitch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindowstrueに設定します:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true);

このスイッチは、Windows 上の .NET Core 2.1 以降および .NET Standard 2.0 以降のプロジェクトでマネージド ネットワーク実装を使用するようにドライバーの動作を切り替え、Microsoft.Data.SqlClient ライブラリのネイティブ ライブラリへの依存関係をすべて排除します。 これはテストとデバッグのみを目的としています。

注意

ネイティブ実装と比較すると、いくつかの既知の相違点があります。 例えば、管理された実装は非ドメインのWindows認証をサポートしていません。

透過的なネットワーク IP の解決を無効にする

適用対象: .NET Framework

透過的なネットワーク IP の解決 (TNIR) は、既存の MultiSubnetFailover 機能の改訂です。 TNIR は、ホスト名の解決された最初の IP が応答せず、ホスト名に複数の IP が関連付けられている場合に、ドライバーの接続シーケンスに影響を及ぼします。 TransparentNetworkIPResolutionとMultiSubnetFailoverの組み合わせは接続シーケンスを選択します:

TransparentNetworkIPResolution MultiSubnetFailover 接続シーケンス
True True TransparentNetworkIPResolution は無視されます。 ドライバーはDNSで解決されたIPアドレスを並列に試み、最初の応答者との認証を完成させます。
True 偽 ドライバーはDNSで解決されたIPアドレスに対して複数回の接続ラウンドを実行し、初回の試みは最低500ミリ秒、そして接続成功または全体の Connect Timeout に達するまで、1回目のタイムアウトは徐々に大きくなります。
偽 True ドライバーはDNSで解決されたIPアドレスを並列に試み、最初の応答者との認証を完成させます。
偽 偽 ドライバーは、DNS で解決された各 IP アドレスへの接続を順に試み、いずれかが成功するか、Connect Timeout に達するまで続行します。

TransparentNetworkIPResolution.NET Frameworkではデフォルトで有効であり、MultiSubnetFailoverはデフォルトで無効化されています。 .NET 5以降のバージョンでは、TransparentNetworkIPResolutionは認識された接続文字列キーワードではなく、任意の値で設定するとArgumentException(KeywordNotSupported)が投げられます。 これらのバージョンは MultiSubnetFailover のみをサポートします。 このセクションの残りの部分(自動オーバーライド、以下の警告の故障モード、およびAppContextスイッチ)は.NETフレームワークに適用されます。

ヒント

.NET のバージョンや、対象が Azure SQL かオンプレミスの SQL Server かどうかに関係なく、すべての接続文字列でMultiSubnetFailover=Trueを設定してください。 MultiSubnetFailover=True 最初のレスポンシブレプリカを素早く見つける並列接続コードパスを選択します。 .NETフレームワークでは、TNIRの逐次的なIPごとの再試行ループも回避します。これは長い接続遅延や認証前のハンドシェイクタイムアウトの一般的な原因です。

.NET Frameworkでは、接続文字列でTransparentNetworkIPResolutionが指定されていない場合、データソースが認識されたAzure SQLエンドポイントである場合、Authenticationキーが任意のMicrosoft Entra IDメソッド(Active Directory Password、Active Directory Integrated、Active Directory Interactive、Active Directory Service Principal、Active Directory Device Code Flow、Active Directory Managed Identity、Active Directory MSI、Active Directory Default、またはActive Directory Workload Identity)に設定されている場合、またはSqlConnection.AccessTokenプロパティが設定されている場合、ドライバーは自動的にTNIRを無効化します。 ドライバーが認識するエンドポイント接尾辞については、SqlConnection.ConnectionString の TransparentNetworkIPResolution エントリを参照してください。

明示的な TransparentNetworkIPResolution 値はこの自動動作を回避します。 True TNIRを有効にし、 False 無条件にTNIRを無効化します。 自動動作を復元するには、そのキーワードを接続文字列から削除してください。 また、接続文字列がカスタムCNAMEやvanity DNS名を通じてAzure SQLを指し示し、その接尾辞がAzure SQLエンドポイントとして認識されていない場合も自動オーバーライドは適用されません。 自動オーバーライドは特にAzure SQLを対象としており、オンプレミスのSQL Serverでは起動しないため、TNIRはデフォルトでオンになっています。

.NETフレームワーク上の長い接続遅延

.NET Frameworkでは、TransparentNetworkIPResolution=True(デフォルト)は、ターゲットDNS名が複数のIPに解決され、初期のIPの一つが不健康、古く、または到達不能になると、長い接続遅延や認証前のハンドシェイクタイムアウトを引き起こすことがあります。 TNIRは解決されたIPを順次に試行し、各ラウンドごとにタイムアウトを増やし、全体の Connect Timeout に達するまで続けます。 通常、予想外に長い接続遅延が起こり、その結果は以下のエラーで終わります:

Connection Timeout Expired.  The timeout period elapsed while attempting to consume the pre-authentication handshake acknowledgement.  This could be because the pre-authentication handshake failed or the server was unable to respond back in time.

このパターンはいくつかのトポロジーで現れます:

  • Azure SQL Database、Azure SQL Managed Instance、またはMicrosoft FabricのSQL Database。 Azure SQLゲートウェイは各認証をバックエンドレプリカにルーティングします。 ルーティング接続が失敗すると、TNIRはゲートウェイに戻らずにルーティングされたバックエンドを再試行するため、バックエンドフェイルオーバー中の遅延が延長されます。
  • DNS 名が複数のレプリカ IP に解決される Always On 可用性グループ リスナーの背後にあるオンプレミス SQL Server。 古いDNSエントリや不健康なレプリカIPは、TNIRが動作するレプリカに到達する前に順次試行されます。
  • マルチサブネットクラスタリスナーを持つフェイルオーバークラスタインスタンスや、ターゲットDNS名に複数の A/AAAA レコードを持つその他の構成(DNSラウンドロビンなど)などです。

この挙動を避けるために、接続文字列にMultiSubnetFailover=Trueを設定します:

MultiSubnetFailover=True

この推奨はすべての.NETバージョンで機能し、Azure SQLとオンプレミスのSQL Serverの両方をカバーしています。 MultiSubnetFailover=True時、ドライバはTransparentNetworkIPResolutionを無視し、DNSで解決されたIPアドレスを並列に試み、最初のレスポンシブレプリカとの認証を完成させます。 名前に反して、 MultiSubnetFailover は複数のターゲットIPにDNS名で解決されるリスナーに適用されます。IPが異なるサブネットに属していなくても、DNSが単一のIPに解決されるスタンドアロンサーバーでは安全です。

すべての接続文字列を編集せずにプロセス全体で制御する場合は、デフォルトのAppContextスイッチでEnable MultiSubnetFailoverをご利用ください。

AppContextスイッチでTNIRを無効にする

.NET Framework上でTransparentNetworkIPResolutionのデフォルト値をtrueからfalseに反転させるには、アプリケーション起動時にAppContextのスイッチSwitch.Microsoft.Data.SqlClient.DisableTNIRByDefaultInConnectionStringをtrueに設定してください。 このスイッチは接続文字列にTransparentNetworkIPResolutionがない時のみデフォルト値を変更し、明示的な値を上書きしません。

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.DisableTNIRByDefaultInConnectionString", true);

これらのプロパティの設定方法の詳細については、「SqlConnection.ConnectionString プロパティ」を参照してください。

ログイン時の最小タイムアウトを無効にしてください

適用対象: .NET Framework、.NET、.NET Standard

デフォルトでは、SqlClientはログイン試行の利用可能な時間を計算する際に最低1秒の時間制限を設けています。 この動作により、計算されたタイムアウトがゼロに切り下げられてもログイン試行が無期限に待つことを防げます。

レガシー動作を復元するには、AppContextスイッチ Switch.Microsoft.Data.SqlClient.UseOneSecFloorInTimeoutCalculationDuringLogin をアプリケーション起動時に false に設定してください:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseOneSecFloorInTimeoutCalculationDuringLogin", false);

ReadAsync のブロック動作を無効にする

適用対象: .NET Framework、.NET、.NET Standard

バージョン3.0からは非同期 ReadAsync 動作します。 以前のバージョンでは、ReadAsync を同期的に実行し、.NET Framework 上では呼び出しスレッドをブロックします。 このブロッキング動作を制御するには、アプリ起動時にAppContextスイッチ Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking を true または false に設定してください:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking", false);

rowversionのnull動作を有効にする

適用対象: .NET Framework、.NET、.NET Standard

バージョン3.0以降、rowversionにnull値がある場合、SqlDataReaderは空のbyte[]ではなくDBNull値を返します。 空 byte[]を返すというレガシー動作を有効にするには、アプリケーション起動時にAppContextスイッチ Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior を有効にしてください。

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior", true);

安全でない TLS 警告の抑制

適用対象: .NET Framework、.NET、.NET Standard

(バージョン 4.0.1 以降で使用できます)

接続文字列でEncrypt=falseを使うと、TLSバージョンが1.2以下の場合、コンソールはセキュリティ警告を表示します。 この警告を抑制するには、アプリケーション起動時に以下のAppContextスイッチを有効にしてください:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning", true);

サーバーが提供するフェールオーバーパートナーを無視する

適用対象: .NET Framework、.NET、.NET Standard

(バージョン 5.1.8、6.0.4、6.1.3 以降で使用可能)

フェールオーバー時に、サーバーから提供されるフェールオーバー パートナー情報は、接続文字列で提供されるフェールオーバー パートナー情報よりも優先されます。 サーバーによって提供されるフェールオーバー パートナー情報を無視し、接続文字列で提供されるフェールオーバー パートナー情報のみを考慮するには、アプリケーションの起動時に次の AppContext スイッチを有効にします。

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.IgnoreServerProvidedFailoverPartner", true);

接続のアイドル タイムアウトを適用する

適用対象: .NET Framework、.NET、.NET Standard

バージョン7.1.0以降、Connection Idle Timeout 接続文字列キーワードとSqlConnectionStringBuilder.IdleTimeoutプロパティは、プールされた接続に対してアイドル期限チェックやバックグラウンドクリーンアップを構成するようになりました。 既定値は 300 秒です。 マイナス値は例外ArgumentExceptionをスローします。

スイッチおよび接続文字列設定は、各プール実装に異なる影響を与えます:

  • V1プール。 スイッチが trueのとき、V1は歴史的なランダム化された2〜4分のクリーンアップケイデンスを使い、Connection Idle Timeoutに関係なくアイドル接続を排除します。 スイッチが false のとき、かつ Connection Idle Timeout がゼロでない場合、V1は設定されたタイムアウトの半分をクリーンアップの間隔として使い、1〜2回のクリーンアップサイクル後にアイドル接続を追い出します。 スイッチが false および Connection Idle Timeout=0 の場合、V1 はアイドル切断を無効にしますが、従来どおり 2 ~ 4 分間隔でランダムに設定された間隔で、最小プールサイズの維持を継続します。
  • V2プール。 スイッチが true の場合、V2 は接続ごとのアイドル時間チェックを行いませんが、Connection Idle Timeout が 0 以外の場合、バックグラウンド プルーニングが有効になり、構成されます。 スイッチが false で、かつ Connection Idle Timeout が 0 以外の場合、V2 は接続ごとのアイドル時間チェックを実行し、タイムアウトに基づいてバックグラウンド プルーニングを構成します。 スイッチが false および Connection Idle Timeout=0 の場合、V2 は接続ごとのアイドル時間チェックやバックグラウンド プルーニングを実行しません。 V2は、Min Pool Size が Max Pool Size 以上の場合、バックグラウンドプルーニングを実行しません。
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseLegacyIdleTimeoutBehavior", false);

設定例については「接続のアイドル時間の制限」を参照してください。

V2接続プールを有効にしてください

適用対象: .NET Framework、.NET、.NET Standard

バージョン7.1からは、SqlClientには代替の接続プール実装(V2)が含まれています。 V1 プールは引き続きデフォルト設定であり、スイッチのデフォルト値は false のままです。

V2 を有効にするには、アプリケーションの起動時に AppContext スイッチ Switch.Microsoft.Data.SqlClient.UseConnectionPoolV2 を有効にします:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseConnectionPoolV2", true);

接続文字列 プーリングのコントロールは両方の実装に適用されます。 詳細については、SQL Server connection poolingをご覧ください。

プールの待ち時間やネットワーク接続には1つの接続タイムアウトを使いましょう

適用対象: .NET Framework、.NET、.NET Standard

バージョン7.1.0以降、プールからの接続待ち時間は呼び出し元の Connect Timeout 予算にカウントされるため、プール待ち時間とネットワーク接続試行は1つの全体タイムアウトを共有します。 Switch.Microsoft.Data.SqlClient.UseOverallConnectTimeoutForPoolWaitを有効にすると、いずれの接続プール実装でも全体のタイムアウトを使用できるようになります:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseOverallConnectTimeoutForPoolWait", true);

スイッチはデフォルトで falseになります。 このデフォルト設定では、従来の接続タイムアウトの挙動が維持されます。つまり、プール操作では完全な Connect Timeout が返され、ネットワーク接続の試行では別の完全なタイムアウトが発生します。 その結果、 Open や OpenAsync は設定された Connect Timeoutよりも時間がかかることがあります。

ログインエラー時のレガシーフェイルオーバーの交互に戻す

適用対象: .NET Framework、.NET、.NET Standard

バージョン 7.1.0 以降、フェールオーバーが構成された状態で接続する場合、ログイン フェーズ中に SQL エラーが発生しても、SqlClient はフェールオーバー パートナーに切り替わらなくなりました。 レガシーの交互動作に戻すには、アプリケーション起動時にAppContextスイッチ Switch.Microsoft.Data.SqlClient.UseLegacyFailoverAlternationOnLoginSqlErrors を有効にしてください。 スイッチはデフォルトで falseになります。

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseLegacyFailoverAlternationOnLoginSqlErrors", true);

vartimeパラメータに対して明確なゼロスケールを尊重してください

適用対象: .NET Framework、.NET、.NET Standard

デフォルトでは、 datetime2、 datetimeoffset、 またはtime パラメータのスケールを明示的に0に設定すると、SqlClientはスケール7を送信します。 バージョン6.0以降では、アプリケーション起動時に Switch.Microsoft.Data.SqlClient.LegacyVarTimeZeroScaleBehaviour を false に設定し、明示的なスケール0を保ちます。 スイッチはデフォルトで trueになります。

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.LegacyVarTimeZeroScaleBehaviour", false);