0

语境:

我有十几台服务器。

每台服务器都有一个带有站点的 IIS,该站点每 5 分钟执行一次以下大型 SQL 脚本。

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

每次崩溃后我都需要回收游泳池……目前是我的双手。

因此,该站点存在问题,我认为大型 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个用户,没有crash
  • ETC

问题 :

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

2 回答 2

1

您是否尝试过确保阅读器在使用后也关闭?

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

我不确定是否关闭了连接

using (var connection = new SqlConnection(connectionString))

负责命令和阅读器资源。

于 2013-01-25T12:18:53.470 回答
1

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

我会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;
于 2013-01-25T12:43:58.983 回答