2011-08-12 8 views
1

テーブルoptin_channel_1をJOIN最適クラスタ化インデックスが

CREATE TABLE [dbo].[optin_channel_1](
    [key_id] [bigint] NOT NULL, 
    [valid_to] [datetime] NOT NULL, 
    [valid_from] [datetime] NOT NULL, 
    [key_type_id] [int] NOT NULL, 
    [optin_flag] [tinyint] NOT NULL, 
    [source_proc_id] [int] NOT NULL, 
    [date_inserted] [datetime] NOT NULL 
) ON [PRIMARY] 

CREATE CLUSTERED INDEX [ix_id] ON [dbo].[optin_channel_1] 
(
    [key_type_id] ASC, 
    [key_id] ASC, 
    [valid_to] ASC, 
    [valid_from] 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] 

テーブルprofile_conns

CREATE TABLE [dbo].[profile_conns](
    [profile_key_id] [bigint] NOT NULL, 
    [valid_to] [datetime] NOT NULL, 
    [valid_from] [datetime] NOT NULL, 
    [conn_key_id] [bigint] NOT NULL, 
    [conn_key_type_id] [int] NOT NULL, 
    [conn_type_id] [int] NOT NULL, 
    [source_proc_id] [int] NOT NULL, 
    [date_inserted] [datetime] NOT NULL 
) ON [PRIMARY] 

CREATE CLUSTERED INDEX [ix_id] ON [dbo].[profile_conns] 
(
    [profile_key_id] ASC, 
    [conn_key_type_id] ASC, 
    [conn_key_id] ASC, 
    [valid_to] ASC, 
    [valid_from] 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] 

テーブルlu_channel_conns

CREATE TABLE [dbo].[lu_channel_conns](
    [channel_id] [int] NOT NULL, 
    [conn_type_id] [int] NOT NULL, 
CONSTRAINT [PK_lu_channel_conns] PRIMARY KEY CLUSTERED 
(
    [channel_id] ASC, 
    [conn_type_id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

テーブルlu_conn_type(各 'チャネル' のための専用のテーブルがあります)

CREATE TABLE [dbo].[lu_conn_type](
    [conn_type_id] [int] NOT NULL, 
    [default_key_type_id] [int] NOT NULL, 
    [master_key_type_id] [int] NOT NULL, 
    [date_inserted] [datetime] NOT NULL, 
CONSTRAINT [PK_lu_conns] PRIMARY KEY CLUSTERED 
(
    [conn_type_id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

ビューv_source_proc_id_by_group_id

SELECT DISTINCT x.source_proc_id, x.source_proc_group_id 
FROM lu_source_proc x INNER JOIN lu_source_proc_group y ON x.source_proc_group_id = y.group_id 

実行されようとして、動的SQL文があります:

SET @sql_str='SELECT @ret=MAX(o.optin_flag) 
    FROM optin_channel_'+CAST(@channel_id AS NVARCHAR(100))+' o 
    INNER HASH JOIN dbo.v_source_proc_id_by_group_id y ON o.source_proc_id=y.source_proc_id AND [email protected]_proc_group_id 
    INNER HASH JOIN profile_conns z ON z.profile_key_id=cast(@profile_key_id AS NVARCHAR(100)) AND z.conn_key_type_id=o.key_type_id AND z.conn_key_id=o.[key_id] AND z.valid_to=''01.01.3000'' 
    INNER HASH JOIN lu_channel_conns x ON [email protected]_id AND z.conn_type_id=x.conn_type_id 
    INNER HASH JOIN lu_conn_type ct ON ct.conn_type_id=x.conn_type_id AND ct.default_key_type_id=o.key_type_id' 
SET @param='@channel_id INT, @profile_key_id INT, @source_proc_group_id INT, @ret NVARCHAR(400) OUTPUT' 
EXEC sp_executesql @sql_str,@param,@channel_id,@profile_key_id,@source_proc_group_id,@ret OUTPUT 

すなわち、

SELECT @ret=MAX(o.optin_flag) AS optin_flag 
FROM optin_channel_1 o 
INNER HASH JOIN dbo.v_source_proc_id_by_group_id y 
    ON o.source_proc_id=y.source_proc_id 
    AND y.source_proc_group_id=5 
INNER HASH JOIN profile_conns z 
    ON z.profile_key_id=1 
    AND z.conn_key_type_id=o.key_type_id 
    AND z.conn_key_id=o.[key_id] 
    AND z.valid_to='01.01.3000' 
INNER HASH JOIN lu_channel_conns x 
    ON x.channel_id=1 
    AND z.conn_type_id=x.conn_type_id 
INNER HASH JOIN lu_conn_type ct 
    ON ct.conn_type_id=x.conn_type_id 
    AND ct.default_key_type_id=o.key_type_id 

これらのテーブルはoptinデータベース用に使用されます。 optin_flagは0または1である可能性があります。最後の文では、source_proc_group_id=5に属するプロセスによってoptinがデータベースに挿入されたときに、を持つユーザのchannel_id=1のから1をoptin_flagとして取得したいとします。私はこれが何が起こっているのかを理解するのに十分であることを願っています。

これはCLUSTERED INDEXを使用する最もよい方法ですか?またはprofile_connsのインデックスからprofile_key_idを削除し、WHERE句にz.profile_key_id=1を入れる方が良いでしょうか?

この選択を最適化する方がはるかに良い方法があるかもしれません(データベーススキーマの変更は不可能で、インデックスと変更ステートメントの変更のみです)。

+1

現在の方法でパフォーマンスの問題がありますか、**あなたは**潜在的なパフォーマンスの問題があると思いますか? – JNK

+0

私たちは、今後いくつかの集中テストを計画しています。この動的SQLは、テーブル上の巨大なトリガの一部に過ぎず、トリガが実行されると、このステートメントは30回30回実行されるため、完全な時間の50%以上を消費します。私は200-300ミリ秒のトリガの実行時間を期待しています。しかし、今は約1秒走ります。確かに残りのトリガーはわからないが、SQLよりも時間がかかるので、最適化すべきだと思う。 – rabudde

答えて

3

テーブルのサイズとそこに格納されているデータの種類を知らなくても、測定することは困難です。

  • optin_channel_1(のkey_id)またはkey_type_idにクラスタ化インデックスフィールドが最も異なる値を持っているかに依存:optin_channel_1は、データとprofile_consの多くは、大量のデータを持っていた私は、次のことをしようとするだろうと仮定

    。 (あなたがカバーインデックスを持っていないので)

  • あなたはoptin_channel_1
  • などで選択した内容に応じprofile_conns(cons_key_id)またはcons_key_type_idにクラスタ化インデックス...基本的に

、あなたのテーブルのprofile_conns場合テーブルにはあま​​りデータがありません、私は最も断片化された "フィルタ"フィールド(私は疑わしいprofile_key_id)にクラスタードインデックスを配置します。テーブルに大量のデータがある場合は、ハッシュ/マージ結合を行い、クラスタ化インデックスをoptin_channel_1テーブルのクラスタ化インデックスと照合します。

私ものようなクエリを書き換えます:

SELECT @ret = MAX(o.optin_flag) AS optin_flag 
    FROM optin_channel_1 o 
    JOIN dbo.v_source_proc_id_by_group_id y 
    ON o.source_proc_id = y.source_proc_id 
    JOIN profile_conns z 
    ON z.conn_key_type_id = o.key_type_id 
    AND z.conn_key_id = o.[key_id] 
    JOIN lu_channel_conns x 
    ON z.conn_type_id = x.conn_type_id 
    JOIN lu_conn_type ct 
    ON ct.conn_type_id = x.conn_type_id 
    AND ct.default_key_type_id=o.key_type_id 
WHERE y.source_proc_group_id = 5 
    AND z.profile_key_id = 1 
    AND x.channel_id = 1 
    AND z.valid_to = '01.01.3000' 

クエリは、このように変更したため:

  • 、WHERE句でフィルタ条件を置くことを目指すために、関連する分野が何であるかを示しますハッシュ/マージ結合
  • ジョイントヒントを置くことはまれです。最適なクエリプランを決定するためにクエリガバナを叩くことは非常に困難です。悪い計画は通常、あなたのインデックス/統計に問題があることを示します。

だから要約として:

  • 小さなテーブルが大きなテーブルに結合==>内のフィールドに参加小さなテーブル&で「フィルタ」フィールドにクラスタ化インデックスを集中&ネストされたループのために行きます大きなテーブル。
  • 大きいテーブルに結合された大きなテーブル=>ハッシュ/マージ結合のために移動し、両側の一致するフィールドにクラスタードインデックスを配置します。
  • マルチフィールドインデックスは、通常、照会するすべてのフィールドが索引に含まれています。 (またはinclude()句に含まれています)
+1

+1 'JOIN'ヒントを削除し、フィルターを' WHERE'節に移動するため。 – JNK

+0

私の経験では、条件をジョインにすると、より良いパフォーマンスが得られることがあります。私が開発したデータベースの1つに、1億以上のレコードを持つ複数値の結合テーブル(電子メールのCCリストなど)があり、メインテーブルには約100万個のデータがあります。結合条件の問合せ条件が1億レコード・テーブルを100レコードまでフィルタリングした場合、結合前にフィルタを実行するとパフォーマンスが大幅に向上します。条件が結合に含まれていて、テーブルヒントでその効果を得ることができなかった場合、SQLは結合前にそのフィルタを実行する方が優れていました。 – Paparazzi

+0

@BalamBalam不正なクエリプランにつながる不正確な統計のように聞こえます。クエリガバナは、私が知る限り、まったく同じクエリプランを作成します。私は今週末にダブルチェックを行うためにいくつかのテストを行います。 –

関連する問題