13

私は単純なインデックス付きビューを持っています。それに対してクエリを実行すると、かなり遅いです。まず、スキーマとインデックスを示します。次に、単純なクエリ。最後に、クエリ プランの画面です。

更新: この投稿の下部にあるソリューションの証明。

スキーマ

これはそれがどのように見えるかです:-

CREATE view [dbo].[PostsCleanSubjectView] with SCHEMABINDING AS
    SELECT PostId, PostTypeId, 
        [dbo].[ToUriCleanText]([Subject]) AS CleanedSubject
    FROM [dbo].[Posts]

私の udfToUriCleanTextは、さまざまな文字を空の文字に置き換えるだけです。例えば。すべての「#」文字を「」に置き換えます。

次に、これに2つのインデックスを追加しました:-

インデックス

主キー インデックス (つまり、クラスター化インデックス)

CREATE UNIQUE CLUSTERED INDEX [PK_PostCleanSubjectView] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [PostId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

および非クラスター化インデックス

CREATE NONCLUSTERED INDEX [IX_PostCleanSubjectView_PostTypeId_Subject] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [CleanedSubject] ASC,
    [PostTypeId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

現在、これには約25,000行あります。何も大したことはありません。

次のクエリを実行すると、どちらも約 4 秒かかります。なんてこと?これは..基本的にインスタントです!

クエリ 1

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town'

クエリ 2 (別の where 句項目を追加)

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

私は何を間違えましたか?UDFは物事を台無しにしていますか? このビューにインデックスを付けたので、それが具体化されると思いました。そのため、その文字列列を計算する必要はありません。

これが役立つ場合は、クエリプランのスクリーンショットを次に示します:- 代替テキスト

また、使用しているインデックスに注意してください。なぜそのインデックスを使用しているのですか?

その指数は…

CREATE NONCLUSTERED INDEX [IX_Posts_PostTypeId_Subject] ON [dbo].[Posts] 
(
    [PostTypeId] ASC,
    [Subject] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, 
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

ええ、何かアイデアはありますか?

更新 1: udf のスキーマを追加しました。

CREATE FUNCTION [dbo].[ToUriCleanText]
(
    @Subject NVARCHAR(300)
)
RETURNS NVARCHAR(350) WITH SCHEMABINDING
AS 
BEGIN
   <snip>
   // Nothing insteresting in here. 
   //Just lots of SET @foo = REPLACE(@foo, '$', ''), etc.
END

更新 2: 解決策

うん、ビューでインデックスを使用していなかったので、ビューを展開していないことを手動で確認する必要がありました。サーバーは Sql Server 2008 Standard Edition です。完全な答えは以下です。これが証拠です。WITH (NOEXPAND) 代替テキスト

この問題を解決するのを手伝ってくれてありがとう:)

4

7 に答える 7

20

SQL Server のエディションは? インデックス付きビューを自動的に使用するのは Enterprise Edition と Developer Edition のみであり、他のエディションはクエリ ヒントを使用してサポートしていると思います。

SELECT a.PostId
FROM PostsCleanSubjectView a WITH (NOEXPAND)
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

MSDN の Query Hints (Transact SQL)から:

クエリの SELECT 部分でビューが直接参照され、WITH (NOEXPAND) または WITH (NOEXPAND, INDEX( index_value [ ,...n ] ) ) が指定されている場合にのみ、インデックス付きビューは展開されません。

于 2009-06-17T04:14:10.160 に答える
4

実行計画のクエリ コードに @ 記号が表示されます。関連する文字列変数があります。

文字列変数の型がインデックス内の文字列列の型と一致しない場合、Sql Server は NASTY 動作をします。Sql Serverは...列全体をその型に変換し、高速検索を実行してから、変換されたインデックスを破棄して、次のクエリですべてをやり直すことができます.


サイモンはそれを理解しました - しかし、ここにもっと役立つ詳細があります: http://msdn.microsoft.com/en-us/library/ms187373.aspx

インデックス付きビューとベース テーブルの両方に存在する列への参照がクエリに含まれており、インデックス付きビューを使用することがクエリの実行に最適な方法であるとクエリ オプティマイザーが判断した場合、クエリ オプティマイザーはビューのインデックスを使用します。この関数はインデックス付きビュー マッチングと呼ばれ、SQL Server Enterprise および Developer エディションでのみサポートされています。

ただし、オプティマイザーが一致のためにインデックス付きビューを検討したり、NOEXPAND ヒントで参照されるインデックス付きビューを使用したりするには、次の SET オプションを ON に設定する必要があります。

つまり、ここで起こっているのは、インデックス付きビューの一致が機能していないということです。Sql Server の Enterprise または Developer エディションを使用していることを確認してください (ほとんどの場合)。次に、記事に従ってSETオプションを確認してください。

于 2009-06-17T03:30:32.450 に答える
0

where句で比較を行う前に、すべての行に対してその関数を呼び出す必要があると思います。件名を公開し、それに対してクエリ チェックを直接実行し、時間がどのように機能するかを確認します。関数を使用して値を変更し、それを where 句で使用するたびに、一般的に多くの速度低下が見られます...

于 2009-06-17T03:48:33.350 に答える
0

インデックス付きビューを使用することで、どのような利点を期待していますか? テーブル自体を適切にインデックス化することはできませんか? 正当な理由がなければ、複雑さが増し、オプティマイザに柔軟性の低いより多くのデータベース オブジェクトを処理するように依頼することになります。

標準インデックスで同じクエリ ロジックを評価しましたか?

UDF ロジックを混在させると、さらに混乱します。

于 2009-06-17T03:50:04.020 に答える
0

私は最近、何億もの通話詳細レコードを含む大規模なデータベースを構築しました。クエリやビューで使用していたいくつかの関数を、永続化された計算列に変換しました。計算された列にインデックスを付けることができたので、これははるかにうまく機能しました。

ただし、SQL Enterprise を使用していなかったので、インデックス付きビューを使用する機会がありませんでした。インデックス付きビューは、UDF の確定的な結果にインデックスを付けることができるはずですか?

于 2009-06-17T03:40:43.317 に答える
0

UDF の戻り値を永続化することだけが必要な場合は、インデックス付きビューではなく、永続化された計算列を検討してください。

于 2009-06-17T04:24:12.360 に答える