C# 来自C/ASP.NET的慢速、大型SQL查询

C# 来自C/ASP.NET的慢速、大型SQL查询,c#,sql,sqldatareader,C#,Sql,Sqldatareader,可能重复: 我目前正在尝试创建一个web应用程序,它使用只读访问,允许用户从我们的数据库下载大型文件。该表中有400000条记录,导出时会生成一个50MB.csv文件 在SQL server上运行SELECT*FROM[table]语句大约需要7秒,在托管在不同服务器上的web应用程序上运行大约需要33秒。这是将所有数据读入System.data.SqlClient.SqlDataReader对象 我的问题是,我无法将SqlDataReader转换为.csv文件。将SqlDataReader的

可能重复:

我目前正在尝试创建一个web应用程序,它使用只读访问,允许用户从我们的数据库下载大型文件。该表中有400000条记录,导出时会生成一个50MB.csv文件

在SQL server上运行SELECT*FROM[table]语句大约需要7秒,在托管在不同服务器上的web应用程序上运行大约需要33秒。这是将所有数据读入System.data.SqlClient.SqlDataReader对象

我的问题是,我无法将SqlDataReader转换为.csv文件。将SqlDataReader的每一行转换为字符串并逐行将该字符串输出到文件几乎需要2个小时,这是不可接受的。下面是我用来在web应用程序服务器上创建文件的代码:

    while (rdr.Read())
    {
        string lineout = "";
        for (int index = 0; index < rdr.FieldCount; index++)
            lineout += rdr[index].ToString().Replace(',', ' ') + ',';
        write(lineout, filename); //uses StreamWriter.WriteLine()
    }

一定有更好的办法。我环顾四周,看到了很多建议,基本上是建议执行上述操作来创建文件。这对较小的桌子非常有效,但不是我们每天使用的两个真正大的桌子。有人能给我一个正确的方向吗?

您可以尝试使用一个而不是手动连接字符串来构建您的线条:

//you can test whether it makes any difference in performance declaring a single
//StringBuilder and clearing, or creating a new one per loop
var sb = new StringBuilder();

while (rdr.Read())
{
    for (int index = 0; index < rdr.FieldCount; index++)
        sb.Append(rdr[index].ToString().Replace(',', ' ').Append(',');

    write(sb.ToString(), filename); //uses StreamWriter.WriteLine()
    sb.Clear();
}
或者,尝试直接写入文件,避免先在内存中生成每一行:

//assume a StreamWriter instance has been created called sw...
while (rdr.Read())
{
    for (int index = 0; index < rdr.FieldCount; index++)
    {
        sw.Write(rdr[index].ToString().Replace(',', ' ');
        sw.WriteLine(",");
    }
}

//flush and close stream

您可以尝试使用字符串而不是手动连接字符串来构建线条输出:

//you can test whether it makes any difference in performance declaring a single
//StringBuilder and clearing, or creating a new one per loop
var sb = new StringBuilder();

while (rdr.Read())
{
    for (int index = 0; index < rdr.FieldCount; index++)
        sb.Append(rdr[index].ToString().Replace(',', ' ').Append(',');

    write(sb.ToString(), filename); //uses StreamWriter.WriteLine()
    sb.Clear();
}
或者,尝试直接写入文件,避免先在内存中生成每一行:

//assume a StreamWriter instance has been created called sw...
while (rdr.Read())
{
    for (int index = 0; index < rdr.FieldCount; index++)
    {
        sw.Write(rdr[index].ToString().Replace(',', ' ');
        sw.WriteLine(",");
    }
}

//flush and close stream

你确定不是SQL变慢了吗?假设你是在服务器上运行的?运行查询时,机器的性能如何反应?您没有在任何地方使用数据集,是吗?这是一个次要问题,但最好使用StringBuilder连接字符串,而不是使用lineout+=rdr[index]。。。由于字符串实例是不可变的,如果使用+=,每个循环都会创建一个新字符串,而stringbuilder是为这样的操作而设计的,对内存分配器的压力会小得多。@GarethD-不一定是小点,尤其是当FieldCount大于10左右时!你确定不是SQL变慢了吗?假设你是在服务器上运行的?运行查询时,机器的性能如何反应?您没有在任何地方使用数据集,是吗?这是一个次要问题,但最好使用StringBuilder连接字符串,而不是使用lineout+=rdr[index]。。。由于字符串实例是不可变的,如果使用+=,每个循环都会创建一个新字符串,而stringbuilder是为这样的操作而设计的,对内存分配器的压力会小得多。@GarethD-不一定是小点,尤其是当FieldCount大于10左右时!当然,使用StringBuilder比连接字符串更有效。没有无用的内存分配,没有多余的内存碎片,我的第二种方法是我使用的。尽管我这样做是为了让它用引号分隔,用逗号分隔。sw.Write\{0}\{1},rdr[index],index==rdr.FieldCount-1?:,;那么我就不必担心值中的逗号,我已经知道字符串中没有逗号,我也不必打电话给字符串你是个漂亮的人,丹尼尔。非常感谢。使用您提供的StreamWriter代码,执行时间不超过40秒。使用StringBuilder肯定比串联字符串更有效。没有无用的内存分配,没有多余的内存碎片,我的第二种方法是我使用的。尽管我这样做是为了让它用引号分隔,用逗号分隔。sw.Write\{0}\{1},rdr[index],index==rdr.FieldCount-1?:,;那么我就不必担心值中的逗号,我已经知道字符串中没有逗号,我也不必打电话给字符串你是个漂亮的人,丹尼尔。非常感谢。使用您提供的StreamWriter代码,执行时间不超过40秒。