大型SQL脚本每5分钟调用一次崩溃IIS池?

时间:2013-01-25 11:24:40

标签: c# .net sql performance iis

上下文:

我有十几台服务器。

每个服务器都有一个IIS,其网站执行以下大型SQL脚本每5分钟

在某些服务器上,承载网站的池崩溃。该池仅包含此站点。

我需要在每次撞车后回收游泳池......目前用我的双手。

因此,网站存在问题,我认为是使用大型SQL脚本。

调用SQL脚本的C#代码:

string root = AppDomain.CurrentDomain.BaseDirectory;
string script = File.ReadAllText(root + @"..\SGBD\select_user_from_all_bases.sql").Replace("$date", dtLastModif);
string connectionString = @"Data Source=(local);Integrated Security=SSPI";

using (var connection = new SqlConnection(connectionString))
{
    connection.Open();

    var command = new SqlCommand(script, connection);
    var reader = command.ExecuteReader();

    var users = new List<UserModel>();

    while (reader.Read())
    {
        users.Add(new UserModel()
        {
            dbName = String.Format("{0}", reader[0]),
            idExternal = int.Parse(String.Format("{0}", reader[1])),
            firstname = String.Format("{0}", reader[2]),
            lastname = String.Format("{0}", reader[3]),
            login = String.Format("{0}", reader[4]),
            password = String.Format("{0}", reader[5]),
            dtContractStart = reader[6] != DBNull.Value ? (DateTime?)reader[6] : null,
            dtContractEnd = reader[7] != DBNull.Value ? (DateTime?)reader[7] : null,
            emailPro = String.Format("{0}", reader[8]),
            emailPerso = String.Format("{0}", reader[9])
        });
    }

    return users;
}

和SQL脚本:

USE master

DECLARE db_names CURSOR FOR
    SELECT name FROM sysdatabases WHERE [name] LIKE 'FOO_%' AND [name] NOT LIKE 'FOO_TRAINING_%'

DECLARE @db_name NVARCHAR(100)
DECLARE @query NVARCHAR(MAX)
DECLARE @queryFinal NVARCHAR(MAX)
SET @query = ''
OPEN db_names 

FETCH NEXT FROM db_names INTO @db_name

WHILE @@FETCH_STATUS = 0
BEGIN

    SET @query = @query + 'SELECT ''' + @db_name + ''', id_salarie, nom, prenom, login COLLATE SQL_Latin1_General_CP1_CI_AS, password COLLATE SQL_Latin1_General_CP1_CI_AS, date_arrivee, date_depart, email COLLATE SQL_Latin1_General_CP1_CI_AS, persoMail COLLATE SQL_Latin1_General_CP1_CI_AS FROM [' + @db_name + '].dbo.utilisateurs WHERE dt_last_modif >= ''$date'' UNION '

    FETCH NEXT FROM db_names INTO @db_name

END

DEALLOCATE db_names 
SET @queryFinal = left(@query, len(@query)-6)
    EXEC sp_executesql @queryFinal

有关服务器的更多信息:

  • Server0:8个数据库,1050个用户,没有崩溃
  • Server1:88个数据库,18954个用户,经常崩溃
  • Server2:109个数据库,21897个用户,经常崩溃
  • Server3:26个数据库,1612个用户,没有崩溃

问题:

  • 脚本有什么问题?知道如何阻止崩溃吗?
  • 如果没有解决方案,我该如何自动回收游泳池?

2 个答案:

答案 0 :(得分:1)

您是否尝试过在使用后读取器被隐藏起来?

using(var reader = command.ExecuteReader()) { ...

如果关闭连接

,我不是舒尔

using (var connection = new SqlConnection(connectionString))

负责命令和读者资源。

答案 1 :(得分:1)

我会在这里做一些事情......如果你的问题是那么持久。首先,我不会生成一个完整的SQL查询,试图一次性从所有这些表中获取数据。接下来,查询正在查询,并暗示可能正在尝试锁定与查询相关联的记录以进行可能的更新...即使您可能不会这样做。

我会在from表中添加WITH (NOLOCK)

select columns from yourTable WITH(NOLOCK) where...

这可以防止锁定与查询关联的所有页面的任何开销。

现在,如何更好地处理循环。在你的fetch循环之前,我会立即创建一个预期输出结果的临时表...类似于

(不确定您的结构的列名长度......

create #C_TempResults
  ( fromDBName char(20), 
    id_salarie int,
    nom char(10),
    prenom char(10),
    login char(10),
    password char(10),
    date_arivee datetime,
    date_depart datetime,
    email char(60),
    persoMail char(60) );

然后,在你已循环遍历所有正在查询的表的循环中,而不是构建一个连续的SQL语句以在最后执行,只需运行一个时间,并插入临时表,如..

(same beginning to prepare your fetch cursor...)
BEGIN
       SET @query = 'INSERT INTO #C_TempResults '
                 + ' SELECT ''' + @db_name + ''' as fromDBName, id_salarie, nom, prenom, '
                       + 'login COLLATE SQL_Latin1_General_CP1_CI_AS, '
                       + 'password COLLATE SQL_Latin1_General_CP1_CI_AS, '
                       + 'date_arrivee, date_depart, '
                       + 'email COLLATE SQL_Latin1_General_CP1_CI_AS, '
                       + 'persoMail COLLATE SQL_Latin1_General_CP1_CI_AS '
                 +  'FROM [' + @db_name + '].dbo.utilisateurs WITH (NOLOCK) '
                 +  'WHERE dt_last_modif >= ''$date'' ';

        -- Run this single query now, get the data and release any "lock" resources
        EXEC sp_executesql @queryFinal

        -- now, get the next database to query from and continue
        FETCH NEXT FROM db_names INTO @db_name
END

DEALLOCATE db_names 

-- FINALLY, just run your select from the temp table that has everything all together...
select * from #C_TempResults;

-- and get rid of your "temp" table
drop table #C_TempResults;