web-dev-qa-db-ja.com

サーバーレベルでのSQLServer実行プラン

ケース:データベースから検索を行っているアプリケーションがあります。それは非常にゆっくりと進んでいます(40秒以上)。トレースでクエリをキャッチしました。 SSMSでクエリを実行すると2〜3秒かかりますが、実行プランをオンにすると40秒以上かかります。設計によるアプリケーションは、2つの異なる言語(照合)を提供します。調査の結果、言語が英語(デフォルトの照合)の場合、アプリケーションは「できるだけ速く」(6〜7秒)動作することがわかりましたが、言語が変更されると、明らかに、SQLサーバーが再コンパイルを実行し、毎回の応答が40秒を超えます。

質問:照合順序を変更した後、どういうわけか再コンパイルを回避できますか?

SQL Server2014。

1
Darko Milic

ここにいくつかの紛らわしい情報があります。たとえば、これは意味がありません。

実行プランをオンにすると、40秒以上になります。

「実行プランをオンにする」とはどういう意味ですか? SSMSの[実際の実行プランを含める]オプションについて話している場合は、そうです。SSMSがグラフィカルな実行プランを準備して描画するのに少し時間がかかります。また、このオプションを初めて有効にすると、さらに時間がかかります。クエリを数回実行しましたか?

また、あなたは言う:

SSMSでクエリを実行すると、2〜3秒かかります

しかし、それから言う:

言語が英語(デフォルトの照合)の場合、アプリケーションは「できるだけ速く」機能することがわかりました(6〜7秒)

2〜3秒は「できるだけ速く」ではないでしょうか。または、アプリケーションはその処理に3〜5秒を追加していますか?

どちらにしても:

言語が変更されると、明らかに、SQLサーバーが再コンパイルを実行し、毎回の応答が40秒を超えます。

いいえ、「明らかに」ではありません。再コンパイルでは、実行ごとに30秒以上の違いは説明されません。しかし、彼らはどのように照合を変更していますか?これは動的SQLであり、何も使用していないか、_COLLATE Latin1_General..._を使用していて、他の言語に_COLLATE other_lang..._を使用していますか?クエリの照合順序を他にどのように変更できるかわかりません。それでも、この違いを説明できる1つのことは、実際に「照合順序」が今説明した方法で変更されている場合)、列にインデックスが付けられているかどうかです。この場合、列の照合順序は_[SQL_]Latin1_General_..._なので、インデックスも英語に基づいて並べられます。たとえば、_COLLATE French_..._を使用して別の照合を強制するクエリが送信された場合、行の順序が異なる可能性があるため、クエリはインデックスを使用できません。

何が起こっているかについて私が正しければ(OPは、状況がここで説明したとおりであることを確認しました)、インデックスを作成する唯一の方法は複数の照合順序を持つ列は、提供されている各言語の照合順序を強制するために、永続化されていない計算列を作成することです。したがって、1つの列を次のようにすることができます。

_ALTER TABLE [dbo].[SomeTable]
  ADD [ColumnNameFrench] AS ([ColumnName] COLLATE French_100_...);
_

その後:

  1. _[ColumnNameFrench]_に非クラスター化インデックスを作成します
  2. アプリのコード/クエリを更新して、誰かが「英語」を選択した場合は_[ColumnName]_から選択し、ユーザーが「フランス語」を選択した場合は代わりに_[ColumnNameFrench]_から選択するようにします。その後、_[ColumnNameFrench]_のインデックスを使用できるようになります。

インデックスのコピーが10個多いと思うので、あまり多くの言語オプションを提供しないことを願っています。

[〜#〜] example [〜#〜]

テーブル:

_-- DROP TABLE #Test;
CREATE TABLE #Test
(
  [TestID] INT IDENTITY(1, 1) PRIMARY KEY,
  [SomethingEnglish] NVARCHAR(50) COLLATE Latin1_General_100_CI_AS_SC,
  [SomethingFrench] AS ([SomethingEnglish] COLLATE French_100_CI_AS_SC),
  [SomethingHebrew] AS ([SomethingEnglish] COLLATE Hebrew_100_CI_AS_SC)
);

CREATE INDEX [IX_#Test_SomethingEnglish] ON #Test ([SomethingEnglish]);
CREATE INDEX [IX_#Test_SomethingFrench] ON #Test ([SomethingFrench]);
CREATE INDEX [IX_#Test_SomethingHebrew] ON #Test ([SomethingHebrew]);
_

簡単なストアドプロシージャ:

_GO
CREATE PROC dbo.Search
(
  @Search  NVARCHAR(500),
  @Language INT
)
AS
SET NOCOUNT ON;

DECLARE @SQL NVARCHAR(MAX);

SET @SQL = N'
SELECT tmp.[TestID]
FROM   #Test tmp
WHERE  tmp.[Something' + 
CASE @Language
  WHEN 1 THEN N'Hebrew'
  WHEN 2 THEN N'French'
  ELSE N'English'
END + N'] = @SearchTerm;';

EXEC sp_executesql
  @SQL,
  N'SearchTerm NVARCHAR(500)',
  @SearchTerm = @Search;
GO
_
2
Solomon Rutzky

ここを完全に読んでください

アプリケーションで遅い、SSMSで速い?

最初に試すことの1つ異なるSETOPTIONS =異なるクエリプランである可能性があります

アプリケーションはARITHABORT = OFF;

SSMS default = ON…このSET ARITHABORT OFFを実行して、アプリからのクエリを模倣し、時間が一致するかどうかを確認できます

1
Jerry Hung