Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# SqlDataReader内部SqlCommand内部SqlCommand_C#_Sql Server - Fatal编程技术网

C# SqlDataReader内部SqlCommand内部SqlCommand

C# SqlDataReader内部SqlCommand内部SqlCommand,c#,sql-server,C#,Sql Server,我有一些代码如下所示: using (SqlConnection sqlCon = new SqlConnection("connection string which includes MultipleActiveResultSets=True") { using (SqlCommand sqlCmd1 = new SqlCommand("SELECT * FROM MyTable WHERE ProcessedRslt IS NULL", sq

我有一些代码如下所示:

using (SqlConnection sqlCon = new SqlConnection("connection string which includes MultipleActiveResultSets=True")
{
    using (SqlCommand sqlCmd1 = new SqlCommand("SELECT * FROM MyTable WHERE ProcessedRslt IS NULL", sqlCon)
    {
        using (SqlDataReader sqlRdr = sqlCmd1.ExecuteReader())
        {
            using (SqlCommand sqlCmd2 = new SqlCommand("UPDATE MyTable SET ProcessedRslt = @Result WHERE RecordID = @RecordID", sqlCon)
            {
                sqlCmd2.Parameters.Add("@RecordID", SqlDbType.Int);
                sqlCmd2.Parameters.Add("@Result", SqlDbType.Int);

                while (sqlRdr.Read())
                {
                    int result = ProcessRecord(sqlRdr["RecordID"], ...) // <- This function takes a bunch of values from the SqlDataReader, performs some fairly complex operations on them and returns a result indicating success or what type failure was encountered.

                    sqlCmd2.Parameters["@RecordID"].Value = (int)sqlDataReader["RecordID"];
                    sqlCmd2.Parameters["@Result"].Value = result;
                    sqlCmd2.ExecuteNonQuery(); // !!!THIS IS THE LINE I'M CONCERNED ABOUT!!!
                }                    
            }
        }
    }
}
UPDATE t
SET ProcessedRslt = ProcessRecord(t.RecordID, ...)
FROM MyTable t
WHERE ProcessedRslt IS NULL
使用(SqlConnection sqlCon=newsqlconnection(“包含MultipleActiveResultSets=True的连接字符串”)
{
使用(SqlCommand sqlCmd1=new SqlCommand(“从ProcessedRslt为NULL的MyTable中选择*”,sqlCon)
{
使用(SqlDataReader sqlRdr=sqlCmd1.ExecuteReader())
{
使用(SqlCommand sqlCmd2=new SqlCommand(“更新我的表格集PROCESSELT=@Result,其中RecordID=@RecordID”,sqlCon)
{
sqlCmd2.Parameters.Add(“@RecordID”,SqlDbType.Int);
sqlCmd2.Parameters.Add(“@Result”,SqlDbType.Int);
while(sqlRdr.Read())
{

int result=ProcessRecord(sqlRdr[“RecordID”],…)/我建议您将
sqlCmd1
sql命令分页,以避免可能的超时。服务器可以关闭长时间的活动连接。

为此需要两个连接,或者使用
Fill()
将第一个查询的结果转换为一个
数据表
,因此您可以在初始查询完全完成后循环返回结果1。SQL ADO.net提供程序在同一连接上支持多个活动结果集,但这将在第一个查询运行时更改结果。这可能会造成死锁服务器上的情况,而您确实不希望出现这种情况

如果您可以将
ProcessRecord()
逻辑移动到T-SQL,则更好,如下所示:

using (SqlConnection sqlCon = new SqlConnection("connection string which includes MultipleActiveResultSets=True")
{
    using (SqlCommand sqlCmd1 = new SqlCommand("SELECT * FROM MyTable WHERE ProcessedRslt IS NULL", sqlCon)
    {
        using (SqlDataReader sqlRdr = sqlCmd1.ExecuteReader())
        {
            using (SqlCommand sqlCmd2 = new SqlCommand("UPDATE MyTable SET ProcessedRslt = @Result WHERE RecordID = @RecordID", sqlCon)
            {
                sqlCmd2.Parameters.Add("@RecordID", SqlDbType.Int);
                sqlCmd2.Parameters.Add("@Result", SqlDbType.Int);

                while (sqlRdr.Read())
                {
                    int result = ProcessRecord(sqlRdr["RecordID"], ...) // <- This function takes a bunch of values from the SqlDataReader, performs some fairly complex operations on them and returns a result indicating success or what type failure was encountered.

                    sqlCmd2.Parameters["@RecordID"].Value = (int)sqlDataReader["RecordID"];
                    sqlCmd2.Parameters["@Result"].Value = result;
                    sqlCmd2.ExecuteNonQuery(); // !!!THIS IS THE LINE I'M CONCERNED ABOUT!!!
                }                    
            }
        }
    }
}
UPDATE t
SET ProcessedRslt = ProcessRecord(t.RecordID, ...)
FROM MyTable t
WHERE ProcessedRslt IS NULL

这可能至少要快一个数量级

如果您能够简化逻辑,使其能够与
更新
内联处理,那就更好了



1这里的缺点是事物不再是原子的。

什么连接是
sqlCmd2
运行的?它在代码中没有显示为在任何连接上运行,在这种情况下不:它将不工作;如果它是
sqlCon
,那么…这是一种不好的做法;如果启用了MARS,它可以工作,但实际上不应该启用MARS-一个单独的示例首选连接(是的:我看到您的评论中启用了MARS,但是…)-所以:它应该可以工作,但是:超时偶尔会发生;至于原因:你需要看看具体的场景-采取了什么锁,服务活动,等等对不起,这是我的疏忽。它使用与SqlCmd1相同的连接。我编辑了这个问题以反映这一点。因此,如果你说这是一种不好的做法,你能给我指一个有足够的惯用方法来执行上述操作吗?为了避免MARS:只需打开第二个连接并将其用于内部命令谢谢,这很有意义……有点。我想弄清楚“但这将在第一个查询运行时改变结果”。我想
sqlCmd1.ExecuteReader()
命令运行实际查询,而
while(sqlRdr.Read())
循环只是对返回的结果集进行迭代。因此,当执行更新时,它确实会更改第一个查询的结果,但第一个查询已经完成,所以这无关紧要。我是否搞错了?SqlDataReader
到底做了什么?它是否会针对实际的SQL db连续执行?ExecuteReader()从不下载完整的结果集。Sql Server通常需要将所有结果具体化到RAM中以满足查询,但即使发生这种情况,ExecuteReader()仍然一次只能从Sql Server检索一条记录。
Read()
向数据库发送命令以下载下一条记录。此外,对于允许下载的查询,ExecuteReader()将从Sql Server中获取可用的结果,因此Sql Server也不需要为整个结果集保留RAM。若要继续…可能发生的情况是,Sql Server将在第一次查询时从表中开始流式传输结果,并因此锁定该表,或至少锁定重要的行/页,但随后您要更新在完成查询之前锁定记录,并在更新发生之前阻止客户端。因此更新无法完成,但锁永远不会释放。死锁。