2011-07-18 4 views
2

大規模なデータベーステーブル(SQL Server 2008)を使用していますが、私のフォーラムメッセージはすべて保存されています(テーブルには現在450万以上のエントリがあります)。SQLクエリにタイムアウトが多く発生する

これは、テーブルのスキーマです:私は帰ってくる参照

CREATE TABLE [dbo].[ForumMessage](
    [MessageId] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, 
    [ForumId] [int] NOT NULL, 
    [MemberId] [int] NOT NULL, 
    [Type] [tinyint] NOT NULL, 
    [Status] [tinyint] NOT NULL, 
    [Subject] [nvarchar](500) NOT NULL, 
    [Body] [text] NOT NULL, 
    [Posted] [datetime] NOT NULL, 
    [Confirmed] [datetime] NULL, 
    [ReplyToMessage] [int] NOT NULL, 
    [TotalAnswers] [int] NOT NULL, 
    [AvgRateing] [decimal](18, 2) NOT NULL, 
    [TotalRated] [int] NOT NULL, 
    [ReadCounter] [int] NOT NULL, 
CONSTRAINT [PK_GroupMessage] PRIMARY KEY CLUSTERED 
(
    [MessageId] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

1つの問題は、私はメッセージとそのすべての返信を選択し、私のストアドプロシージャを実行しているとき、私はいつかタイムアウトを取得するということですSQLサーバーからのエラー。

これは私のストアドプロシージャです:「操作が完了する前に経過し、タイムアウト期間タイムアウトの期限が切れたり、サーバーが応答しない」

select fm1.[MessageId] 
     ,fm1.[ForumId] 
     ,fm1.[MemberId] 
     ,fm1.[Type] 
     ,fm1.[Status] 
     ,fm1.[Subject] 
    ,fm1.[Body] 
     ,fm1.[Posted] 
     ,fm1.[Confirmed] 
     ,fm1.[ReplyToMessage] 
     ,fm1.[TotalAnswers] 
     ,fm1.[AvgRateing] 
     ,fm1.[TotalRated] 
     ,fm1.[ReadCounter], 
    Member.NickName AS MemberNickName, Forum.Name as ForumName 
from ForumMessage fm1 LEFT OUTER JOIN 
         Member ON fm1.MemberId = Member.MemberId INNER JOIN 
       Forum On fm1.ForumId = Forum.ForumId 
where MessageId = @MessageId or [email protected] 
order by MessageId 

私は次のようになりますエラー

私は実行計画を見ていましたが、疑わしいと思われるのは、forummessageテーブルのキールックアップでクエリのコストが約75%〜87%私はそれがクラスタ化されているので、理由を理解していないので、もっと効率的になると思っていました)。私はいつもクラスタリングされたインデックスで検索すると、クエリは非常に効率的でなければならないという仮定の下にあった。

メッセージとその返信を受け取るためにこの問題とこのクエリをどのように改善することができますか?

ありがとうございました。

+0

質問に実行計画を含めることはできますか? – Justin

+0

なぜロフトは参加しますか?すべてのメッセージはメンバーからのものでなければなりませんか? – HLGEM

答えて

0

提案が私の心に来る:

  • 醜いORを削除し、条件のためUNIONを追加します(以下のコード)
  • あなたは上の非クラスタ化インデックスを持っている必要がありますReplyToMessage

最後の手段として、非cluインデックスにはMessageIdReplyToMessageを入れてください。 (ここではWhy does this Sql Statement (with 2 table joins) takes 5 mins to complete?を別の質問に対する私の答えを参照してください)


CODE:

select fm1.[MessageId] 
     ,fm1.[ForumId] 
     ,fm1.[MemberId] 
     ,fm1.[Type] 
     ,fm1.[Status] 
     ,fm1.[Subject] 
    ,fm1.[Body] 
     ,fm1.[Posted] 
     ,fm1.[Confirmed] 
     ,fm1.[ReplyToMessage] 
     ,fm1.[TotalAnswers] 
     ,fm1.[AvgRateing] 
     ,fm1.[TotalRated] 
     ,fm1.[ReadCounter], 
    Member.NickName AS MemberNickName, Forum.Name as ForumName 
from ForumMessage fm1 LEFT OUTER JOIN 
         Member ON fm1.MemberId = Member.MemberId INNER JOIN 
       Forum On fm1.ForumId = Forum.ForumId 
where MessageId = @MessageId 
UNION 
select fm1.[MessageId] 
     ,fm1.[ForumId] 
     ,fm1.[MemberId] 
     ,fm1.[Type] 
     ,fm1.[Status] 
     ,fm1.[Subject] 
    ,fm1.[Body] 
     ,fm1.[Posted] 
     ,fm1.[Confirmed] 
     ,fm1.[ReplyToMessage] 
     ,fm1.[TotalAnswers] 
     ,fm1.[AvgRateing] 
     ,fm1.[TotalRated] 
     ,fm1.[ReadCounter], 
    Member.NickName AS MemberNickName, Forum.Name as ForumName 
from ForumMessage fm1 LEFT OUTER JOIN 
         Member ON fm1.MemberId = Member.MemberId INNER JOIN 
       Forum On fm1.ForumId = Forum.ForumId 
where MessageId = @MessageId 
order by MessageId 
+0

OR句がなぜ「醜い」なのですか – CodeMonkey1313

+0

なぜ「OR」が醜いのですか?私がかなりうまくアプローチするように、私はstandartと言うでしょうか、間違っていますか?面白いことに、私はいつも同じ単純な制約のために同じ「OR」をしています。ところで、あなたのクエリは、2つのSELECTのために明らかにテーブルスキャンを2回実行します! – sll

+0

私は実際に足跡がさらに悪化する前に組合を持っていました。あなたは組合がここでもっと良いと確信していますか? –

0

あなたがORDER BY MessageIdをやっている理由、それはとても必要な順序で?

SELECTSELECT FROM Forumにリファームし、Memberに、最後にLEFT JOIN ForumMessageに参加してみてください。したがって、実行中のMS SQL Serverのバージョンによっては、小さいテーブルから大きなテーブルへの並べ替え

+0

はい、正しい順序でデータを返して、データが正しく解析されていることを確認する必要があります。 –

+0

私はちょうどあなたがメッセージIDを使用しているのだろうか、私はどの論理がこのIDを歓迎してはならないと思います – sll

0

SELECTのパフォーマンスを向上させるために、テーブルを再作成してみることもできます。

+0

私はパーティションを追加する場合、これは検索古いメッセージのパフォーマンスに影響を与えますか? –

+0

それはできませんが、実際にはパーティショニングスキームで決定します。そのテーブルを再構築する必要があることを忘れないでください。 MSDNのドキュメントを見ると、テーブルの制約の解除、テーブルの名前の変更、新しいパーティションテーブルの作成、データの移動、制約の再作成、最後に古いテーブルの削除が示されていると思います。 – CodeMonkey1313

0

ReplyToMessageにインデックスを作成します。

CREATE INDEX 
     IX_ForumMessage_ReplyToMessage 
ON  ForumMessage (ReplyToMessage) 

これはおそらく(MessageId上とReplyToMessageのインデックス上PRIMARY KEY上)追求2つのインデックスになりますが、マージまたはハッシュ連結ではなくてcontatenatedあなたが今持っている完全なテーブルスキャン。

+0

私はすでに1つ持っています.... –

+0

@OrA:これはあなたのスクリプトから明らかではありません。クエリプランを投稿してください:SET SHOWPLAN_TEXT ONを実行してから、同じセッションでクエリを実行してください。 – Quassnoi

+0

私は実際にあなたのスクリプトを実行していたが、何らかの理由で、その14%に87%を取った!それははるかに良い!私はそれをさらに低くしようとするか、それとも "尊敬できる"数字ですか? –

関連する問題