【问题标题】:Proper way to loop a SQL Query?循环 SQL 查询的正确方法?
【发布时间】:2015-11-12 22:49:08
【问题描述】:

我有一个通过传入学生班级列表来检索学生成绩的列表,

然后它通过在数据库中查询学生的姓名来提取学生的成绩。这段代码工作正常,但是当 studentList 的大小增加时,这段代码执行起来很慢,

通过 sql 查询循环列表的正确方法是什么?

private List<StudentClass> getStudentGrades(List<StudentClass> studentList)
{
    for (int i =0; i < studentList.Count; i++)
    {
        string sqlcommand = "SELECT StudentGrades FROM Students WHERE StudentName=@StudentName";
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(sqlcommand, conn))
        {
            cmd.Parameters.AddWithValue("@StudentName", studentList[i].StudentName);
            cmd.ExecuteNonQuery();
            SqlDataReader reader = cmd.ExecuteReader();

            while (reader.Reader())
            {
                studentList[i].StudentGrades = int.Parse(reader["StudentGrades"].ToString());
            }
        }
    }

    return studentList;
}

public class StudentClass
{
    public string StudentName {get; set; }
    public int StudentGrades {get; set; }
}

【问题讨论】:

  • 速度慢的原因是它为每个学生调用了一个新查询。发送学生列表并进行基于单个集合的查询会更好。您可能还想看看这个。 blogs.msmvps.com/jcoehoorn/blog/2014/05/12/…
  • cmd.ExecuteNonQuery();没用,只是删除
  • 觉得 -1 对这个问题有点苛刻

标签: c# mysql sql-server


【解决方案1】:

正如其他用户所指出的,您不需要执行非查询。

但更大的问题是您的 SQL 语句一次只返回一个学生的数据。您是否可以使用另一个字段同时选择一个组中的所有学生?即,是否有一个“类”字段或类似的东西,所以你可以这样做:

select studentgrades
  from students
 where class = @class

如果没有,你仍然可以用 in 子句编写一种丑陋的 sql 语句。所以:

select studentgrades
  from studens
 where studentname in ('studentname1', 'studentname2', etc. )

使用这种方法,您可以将代码修改为如下所示:

private List<StudentClass> getStudentGrades(List<StudentClass> studentList)
{
        string studentListParam = "";
        foreach(StudentClass student in studentlist)
        {
           // blah blah stuff to only add comma if not first element
           studentListParam = studentListParam + ", '" + student.StudentName + "';
        }

        string sqlcommand = @"
SELECT StudentName, StudentGrades
  FROM Students
 WHERE StudentName in (" + studentlist + ")";
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(sqlcommand, conn))
        {
            cmd.Parameters.AddWithValue("@StudentName", studentList[i].StudentName);
            cmd.ExecuteNonQuery();
            SqlDataReader reader = cmd.ExecuteReader();

            while (reader.Reader())
            {
                StudentClass student = studentList.Where(s => s.StudentName == string.Parse(reader["StudentName"]);
                student.StudentGrades = int.Parse(reader["StudentGrades"].ToString());
            }
        }
    }

    return studentList;
}

public class StudentClass
{
    public string StudentName {get; set; }
    public int StudentGrades {get; set; }
}

显然,您需要一些空值检查和其他各种错误检查才能真正为生产做好准备,但这应该是一个起点。

(另外,请注意,这种方法不会尝试参数化查询,因此您会损失一点解析时间,但会比您在多个查询中损失的时间少几个数量级。)

【讨论】:

  • 您在选择中缺少StudentName。它应该是...(" + studentListParam + ")...,但studentListParam 在开头会有一个额外的逗号。请改用string.Join。最后这对sql注入开放。
  • 您不应该像这样构建 SQL 字符串。如果其中一个学生姓名中有特殊字符,则可能会导致异常(或更糟的是,在故意 SQL 注入的情况下)。
  • 是的,它对sql注入开放。试图涵盖这一点以及实际的原始问题会使答案过于复杂。因此,“其他位的错误检查,使这个真正的生产准备就绪”评论。
【解决方案2】:
private List<StudentClass> getStudentGrades(List<StudentClass> studentList)
{
    string sqlcommand = "SELECT StudentGrades FROM Students WHERE StudentName=@StudentName";
    var conn = new SqlConnection();
    SqlCommand cmd = new SqlCommand(sqlcommand, conn);
    cmd.Parameters.Add("@StudentName");
    using (conn)
    {
        conn.Open();
        for (int i = 0; i < studentList.Count; i++)
        {
            cmd.Parameters[0].Value= studentList[i].StudentName;
            studentList[i].StudentGrades = (int)cmd.ExecuteScalar();
        }            
    }

    return studentList;
}

注意:您应该在一次查询中检索整个列表,这样会好得多。

【讨论】:

    【解决方案3】:

    首先 - 你没有必要执行你的命令两次。您首先调用ExecuteNonQuery(它没有任何效果,因为ExecuteNonQuery 不返回数据,但它会减慢执行速度,因为请求实际上被传递到SQL Server 并被执行)。然后你调用ExecuteReader,你实际上是从中检索数据。

    第二个问题 - 您正在为每个学生执行新查询。因此,如果列表中有 1000 名学生 - 将执行 1000 个查询。

    考虑先从数据库中获取所有数据,然后相应地更新您的studentList

    类似于首先获取SELECT StudentName, StudentGrades FROM Students,将结果保存到某个字典(或任何你想要的地方),然后循环遍历studentList

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-27
      • 2011-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-26
      • 1970-01-01
      相关资源
      最近更新 更多