SQL 查询出现大量超时
我有一个大型数据库表(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 Server 的超时错误。
这是我的存储过程:
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%(有所不同)(我不明白为什么,因为我将其设置为集群,所以我是希望它会是效率更高)。我总是假设当您在聚集索引上搜索时,查询应该非常有效。
有谁知道我如何改进这个问题和这个查询来获取消息及其回复?
谢谢。
I have a large database table (SQL Server 2008) where i have all my forum messages being stored (The table currently have more than 4.5 million entries).
this is the table schema:
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]
One issue that i see keep coming back is that when i'm running my stored procedure that select a message and all its replies, i get sometime time-outs errors from the SQL server.
This is my stored procedure:
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
the error that i get look like this: "Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding"
I was looking on the execution plan, and the only this that look suspicious is that is see that the query has a cost of about 75%-87% (it varies) on the key lookup in the forummessage table (which i don't understand why, because i set it up as clustered, so i was hoping it will be much more efficient). I was always under that assumption that when you search on clustered index, the query should be very efficient.
Is there anyone has any idea how i can improve this issue and this query to get a message and its replies?
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我想到了两个建议:
OR
并为条件添加一个UNION
(代码如下)ReplyToMessage
上有一个非聚集索引作为最后的手段,请创建一个非聚集索引并放置
MessageId
ANDReplyToMessage在那里。 (请参阅我对另一个问题的回答为什么这个 Sql 语句(有 2 个表连接)需要 5 分钟才能完成?)
代码:
Two suggestions come to my mind:
OR
and add aUNION
for the condition (CODE BELOW)ReplyToMessage
As a last resort, create a non-clustered index and put
MessageId
ANDReplyToMessage
in there. (See my answer to another question here Why does this Sql Statement (with 2 table joins) takes 5 mins to complete?)CODE:
根据您运行的 MS SQL Server 版本,您还可以尝试利用分区表重新创建表以增强 SELECT 性能。
depending on the version of MS SQL Server you're running you could also try recreating the table utilizing partitioned tables to enhance the
SELECT
performance.在
ReplyToMessage
上创建索引:这很可能会导致两次索引查找(通过
MessageId
上的PRIMARY KEY
和MessageId
上的索引>ReplyToMessage)与合并或哈希串联连接,而不是您现在进行的全表扫描。Create an index on
ReplyToMessage
:This will most probably result in two index seeks (over the
PRIMARY KEY
onMessageId
and over the index onReplyToMessage
) contatenated with a merge or hash concatenation, rather than a full table scan which you are having now.为什么你要这样做
ORDER BY MessageId
,排序有那么必要吗?尝试将您的
SELECT
重构为SELECT FROM Forum
,然后加入Member
,最后LEFT JOIN ForumMessage
。所以桌子从小到大排序Why you are doing
ORDER BY MessageId
, is it so necessary ordering?Try to refactory your
SELECT
toSELECT FROM Forum
and than joining theMember
, and finallyLEFT JOIN ForumMessage
. So order tables from small to large