我有一个大型数据库表(SQL Server 2008),我存储了所有论坛消息(该表目前有超过450万个条目)。
这是表架构:
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]
我看到的一个问题是,当我运行我的存储过程选择一条消息及其所有回复时,我会从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 ReplyToMessage=@MessageId
order by MessageId
我得到的错误如下:“超时已过期。操作完成前经过的超时时间或服务器没有响应”
我正在查看执行计划,唯一看起来可疑的是查看该查询在forummessage表中的密钥查找中的成本约为75%-87%(它有所不同)不明白为什么,因为我把它设置为群集,所以我希望它会更有效率)。我总是在这种假设下,当你搜索聚簇索引时,查询应该非常有效。
有没有人知道如何改进此问题以及此查询以获取消息及其回复?
感谢。
答案 0 :(得分:0)
我想到了两个建议:
OR
并为条件添加UNION
(代码如下)ReplyToMessage
作为最后的手段,创建一个非聚集索引并将MessageId
和ReplyToMessage
放在那里。 (请参阅我在这里的另一个问题的答案Why does this Sql Statement (with 2 table joins) takes 5 mins to complete?)
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
答案 1 :(得分:0)
为什么你在做ORDER BY MessageId
,是否需要订购?
尝试重构您的SELECT
至SELECT FROM Forum
,然后加入Member
,最后加入LEFT JOIN ForumMessage
。因此,从小到大订购表
答案 2 :(得分:0)
根据您运行的MS SQL Server的版本,您还可以尝试使用分区表重新创建表,以提高SELECT
性能。
答案 3 :(得分:0)
在ReplyToMessage
上创建索引:
CREATE INDEX
IX_ForumMessage_ReplyToMessage
ON ForumMessage (ReplyToMessage)
这很可能导致两个索引搜索(PRIMARY KEY
上的MessageId
和ReplyToMessage
上的索引)与合并或散列连接相关联,而不是一个完整的表扫描您现在拥有的。