DataReader.Read运行速度非常慢

时间:2019-09-10 09:36:45

标签: c# sql datareader sqlperformance

作为标题,我遇到了与从MS-SQL读取数据有关的问题。 我使用DataReader编写了C#代码,用于检索查询返回的数据并将数据保存到CVS。非常简单,我很确定这段代码没有问题。

我有两个查询。第一个查询是内部联接4表的结果。 第二个查询在选择语句中使用Row_Num和子查询。它们全部返回24列。 第一个查询返回321k条记录。第二个查询返回2300条记录。 我正在使用SQL Server 2008。

问题是当我运行第一个查询时,它运行速度很快。 321k条记录保存到CVS文件,需要8分钟才能完成。但是,使用第二个查询,需要花费26个小时将2300条记录保存到文件中。我输入了登录代码,发现一些记录需要40到50分钟才能读取数据,我不知道为什么。

请看看并给我一些建议。

贝洛是我的代码,也是我所做的

using (var connection = new SqlConnection(connectionstring))
using (var command = new SqlCommand(secondQuery, connection))
{
    connection.Open();
    try
    {
        command.CommandTimeout = 0;
        command.CommandType = CommandType.Text;
        var reader = command.ExecuteReader();
        using (var memoryStream = ExtendedStream.CreateMemoryStream())
        using (TextWriter writer = new StreamWriter(memoryStream, Encoding.UTF8, 65536))    {
            while (reader.Read())
            {
                // using Nlog to log start time begin read data and log what happen on code
                // read property value and save to file
                // using Nlog to log end time read data
            }
        }
        reader.Dispose();
        reader.Close();
    }
    catch (SqlException ex)
    {
        throw ex;
    }
    finally
    {
        command.Dispose();
        connection.Dispose();
        connection.Close();
    }
}

第二个查询

WITH TEMP AS
(
    SELECT ROW_NUMBER() OVER (PARTITION BY SId,PointID ORDER BY UTCSysTime) Record_No, * FROM
    (SELECT
        *
        FROM
        Table_A WITH (NOLOCK)
        WHERE
        StatusID IN (1, 2)
        AND [UTCSysTime] >= @StartTime
        AND [UTCSysTime] <= @EndTime
        UNION
        SELECT
        E.*
        FROM
        Table_A E WITH (NOLOCK)
        INNER JOIN (SELECT
                        SId,
                        PointID,
                        StatusID,
                        UTCSysTime = MIN(UTCSysTime)
                    FROM
                        Table_A WITH (NOLOCK)
                    WHERE
                        StatusID IN (1, 2)
                        AND [UTCSysTime] > @EndTime
                    GROUP BY
                        SId,
                        PointID,
                        StatusID
                    ) E2
            ON E.SId = E2.SId
                AND E.PointID = E2.PointID
                AND E.StatusID = E2.StatusID
                AND E.UTCSysTime = E2.UTCSysTime
    ) T
)

SELECT
    *,
    [PointShortName] = CONVERT(VARCHAR(255), (SELECT TOP 1
                                            ShortName
                                          FROM
                                            Table_B _T
                                            WITH (NOLOCK)
                                          WHERE
                                            _T.PointID = Table_T.PointID
                                         )),
    [Description_Point] = CONVERT(VARCHAR(2000), (SELECT TOP 1
                                            _T.Name
                                           FROM
                                            Table_Point _T
                                            WITH (NOLOCK)
                                           WHERE
                                            _T.PointID = Table_T.PointID
                                            AND _T.DescID = 1
                                          )),
    [Description_1] = CONVERT(VARCHAR(255), (SELECT TOP 1
                                                            Name
                                                         FROM
                                                            Table_C
                                                            WITH (NOLOCK)
                                                         WHERE
                                                            DescID = 1
                                                            AND CatID = [Table_T].[Cat1]
                                                        )),
    [Description_2] = CONVERT(VARCHAR(255), (SELECT TOP 1
                                                            Name
                                                         FROM
                                                            Table_C
                                                            WITH (NOLOCK)
                                                         WHERE
                                                            DescID = 1
                                                            AND CatID = [Table_T].[Cat2]
                                                        )),
    [Description_3] = CONVERT(VARCHAR(255), (SELECT TOP 1
                                                            Name
                                                         FROM
                                                            Table_C
                                                            WITH (NOLOCK)
                                                         WHERE
                                                            DescID = 1
                                                            AND CatID = [Table_T].[Cat3]
                                                        )),
    [Description_4] = CONVERT(VARCHAR(255), (SELECT TOP 1
                                                            Name
                                                         FROM
                                                            Table_C
                                                            WITH (NOLOCK)
                                                         WHERE
                                                            DescID = 1
                                                            AND CatID = [Table_T].[Cat4]
                                                        ))
FROM
    (SELECT
        *
     FROM
        (SELECT 
            a.*
            ,UTCSysTime_End = ISNULL(CASE WHEN b.StatusID = 1
                                                 THEN b.UTCSysTime
                                            END,
                                            CASE WHEN c.StatusID = 1
                                                 THEN c.UTCSysTime
                                            END)

  FROM TEMP a LEFT OUTER JOIN  TEMP b ON a.Record_no = b.Record_no - 1 and a.SId = b.SId and a.PointID = b.PointID
  LEFT OUTER JOIN  TEMP c ON a.Record_no = c.Record_no - 2 and a.SId = c.SId and a.PointID = c.PointID) E
     WHERE
        E.StatusID = 2
        AND [UTCSysTime] >= @StartTime
        AND [UTCSysTime] <= @EndTime
    ) [Table_T]
WHERE
    [UTCSysTime] > @StartTime
    AND [UTCSysTime] <= @EndTime

我试图在SSMS上运行查询,并且两者都工作良好。我尝试使用SQL事件探查器,但是我的帐户没有权限。因此,我将日志放入源代码中。而且我看到一些记录需要50-60分钟才能读取和写入文件。

日志为:

  

2019-09-09 07:48:40.5242 |调试|结束写入行号226 |例外:
  2019-09-09 07:48:40.5522 |调试|开始写行号227 |例外:
  2019-09-09 07:48:40.5802 |调试|结束写行号227 |例外:
  2019-09-09 07:48:40.6072 |调试|开始写行号228 |例外:
  2019-09-09 07:48:40.6352 |调试|结束写行号228 |例外:
  2019-09-09 07:48:40.6632 |调试|开始写行号229 |例外:
  2019-09-09 08:20:50.3977 |调试|结束写行号229 |例外:
  2019-09-09 08:20:50.4337 |调试|开始写行号230 |例外:
  2019-09-09 08:20:50.4667 |调试|结束写行号230 |例外:
  2019-09-09 08:20:50.5047 |调试|开始写行号231 |例外:
  2019-09-09 08:20:50.5387 |调试|结束写行号231 |例外:

1 个答案:

答案 0 :(得分:0)

这里要做的第一件事是确定问题是输入还是输出。为此,我只需要注释掉所有输出代码,就可以了(只显示未注释的代码):

while (reader.Read())
{
    count++;
} 
Console.WriteLine(count);

如果仍然很慢,则问题出在数据库上。我们看不到您的查询,表,索引或数据-因此我们无法帮助您对其进行调整,但是:那是您需要查找的地方。

如果没有输出代码的情况下速度很快,则问题出在您的编写代码中。您显示ExtendedStream.CreateMemoryStream;这似乎不是常规框架的一部分,所以我无法评论它的预期执行方式,但是坦白地说,如果您正在编写文件,我会尝试使用内置框架类型尝试为此-FileStream

我还将最小化Console输出的数量,也许只显示每N行更新N个。您不是要配置控制台。