【问题标题】:Sql timeout Exception although max pool size is set to 1000000尽管最大池大小设置为 1000000,但 Sql 超时异常
【发布时间】:2013-10-23 15:06:08
【问题描述】:

我正在处理一个 asp.net MVC4 项目并使用 SQL Server 2008。我的数据库表包含 100000 行。此外,连接字符串属性的最大池大小设置为 1000000,池设置为 true。

我的表结构如下:

CREATE TABLE tblNews
(
ID int IDENTITY(1,1) NOT NULL,
Url nvarchar(300) UNIQUE NOT NULL,
PubDate datetime NOT NULL,
Active bit NOT NULL,
Hit int NOT NULL,
...
)

还有一个索引如下:

CREATE NONCLUSTERED INDEX indexTblNews_Url
ON tblNews(Url)

我的选择查询是:

CREATE PROC spNewsGet
   @Url nvarchar(300)
AS
   UPDATE tblNews
   SET Hit = Hit + 1
   WHERE Url = @Url
     AND PubDate > GETDATE()
     AND Active = 1;

   SELECT
      *
   FROM tblNews
   WHERE Url = @Url
     AND PubDate > GETDATE()
     AND Active = 1
   ORDER BY PubDate DESC

在评分较低的网站上没有问题,而且效果很好。但是在像 100000 行这样大的数据库和每天有 2000000 个单用户的网站中,它会崩溃。它在三个页面之一引发SqlTimeout 异常。因此,当我单击一个页面时,几乎所有页面都给出了上述异常。

我检查了硬件性能,处理器消耗为 I7 3.6 GHZ 的 %70,内存消耗为 1.5 GB。但是有更多的空内存。我该如何克服这个问题?

任何帮助将不胜感激。

【问题讨论】:

  • 您确定在使用连接后关闭它们吗?您是否检查过您在 SQL Server 中的执行计划,看看您是否正确地利用了您的索引?
  • 嗯,您是按 PubDate 搜索和排序的,为什么不也索引呢?另外,我猜url 不是唯一的列?
  • @Paddy 我关闭了所有连接,我还使用 .net 分析器进行了检查。没有打开的连接。
  • @MikeSmithDev 我忘了包括唯一键。网址也是独一无二的。当我在索引中包含 PubDate 时,它​​会变慢。
  • @Mesut 那么为什么你有一个ORDER BY... 如果你在查询唯一列URL 之后只能返回一行?

标签: c# asp.net sql-server asp.net-mvc


【解决方案1】:

您很可能正在使用SqlConnection。尝试将连接的ConnectionTimeout 属性设置为0 以指示无限超时。如果你没有使用SqlConnection,你可能有一个类似的属性可以设置。

【讨论】:

  • 这不是正确的解决方案,我的期望是数据库变得更快。
  • @Mesut 由于您没有在问题中指定这一点,我怀疑您想要一个快速而肮脏的解决方案。我很高兴听到您了解这是一种解决方法,而不是真正的解决方法。我对你的问题投了赞成票,所以希望有人能帮助你。
【解决方案2】:

它对某些网站快速运行但对其他网站不起作用的一个可能原因是,对于大容量网站,URL 不再具有足够的选择性,现有索引无法正常工作。因此,UPDATE 可能会升级到行锁之外,从而导致对聚集/非聚集索引的争用。

我怀疑连接不足是一个问题 - 将 connection pool max size 设置为超过 32k 是 pointless,并发 SQL 连接也将取决于与 .Net threads 相关的因素。

我不太明白为什么PubDate 是未来日期,但如果PubDate > GETDATE() 和/或Active = 1 显着减少更新查询中的记录数量,那么我也会添加其中一项或两项索引的字段(如适用),即:

CREATE NONCLUSTERED INDEX indexTblNews_Url
ON tblNews(Url, PubDate);

您还复制了查询 - 一次更新,一次选择。您可以通过临时表减少冗余并重新加入其中。

CREATE PROC spNewsGet
@Url nvarchar(300)
AS
  SELECT ID
  INTO #tmp
  FROM tblNews
  WHERE Url = @Url
  AND PubDate > GETDATE()
  AND Active = 1;

  UPDATE tblNews
  SET Hit = Hit + 1
  FROM tblNews INNER JOIN #tmp on #tmp.ID = tblNews.ID;

  -- Consider also using SET TRANSACTION ISOLATION SNAPSHOT or READ UNCOMMITTED here.
  SELECT tblNews.*
  FROM tblNews INNER JOIN #tmp on #tmp.ID = tblNews.ID
  ORDER BY PubDate DESC;
GO

最后,根据评论,您可以考虑在最终选择中删除隔离级别,前提是结果集不用于“关键事务”用途。

【讨论】:

  • 他可能只使用变量而不是 tmp 表,因为它只是一个 ID。
  • 使用 #TempTable 可以获得更高的性能。我必须使用一个变量。但是在选择结果中有更多的列。如何同时选择和设置表格并获取所有结果列?
  • 最后,根据评论,您可以考虑在最终选择上删除隔离级别,前提是结果集不用于“关键事务”用途。我该怎么做?
  • @StuartLC 我明白了。我只是想说DECLARE @id INT。根本没有桌子。
  • Re: 选择中的更多列 - 只需重新连接到基础表。回复:SET TRANSACTION ISOLATION LEVEL SNAPSHOT;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 请注意consequences of the latter。 @MikeSmith 是正确的 - 我错过了 URL 是唯一的 - 根本不需要临时或表变量 - 您可以为 ID 存储一个简单的 INT 变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多