使用多结果集读取数据减少服务器往返,提高性能
先来谈一下什么是多结果集?以及为什么需要它?
假设我们的一个窗体上有多个控件,需要绑定多个数据源。那么传统情况下,我们可以用不同的命令去读取不同的数据,然后分别绑定。这样做本来无可厚非,但如果从性能上考虑的话,就有改进的必要了。
因为每个单独的命令执行都是需要发生一次服务器的往返的,所以如果能够把数据一次性读取到,统一发给用户程序,再在客户端做单独的绑定,这样的设计可以减少服务器往返次数,提高性能。
以下是一些代码和比较
使用DataReader执行单结果集查询:每次返回一个结果集。(这是传统的方式)
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT CustomerID FROM Customers";
conn.Open();
SqlDataReader reader1 = cmd.ExecuteReader();
DataTable tb1 = new DataTable();
tb1.Load(reader1);
listBox1.DataSource = tb1;
listBox1.DisplayMember = "CustomerID";
reader1.Close();
SqlCommand cmd2 = conn.CreateCommand();
cmd2.CommandText = "SELECT OrderID,OrderDate FROM Orders";
SqlDataReader reader2 = cmd2.ExecuteReader();
DataTable tb2 = new DataTable();
tb2.Load(reader2);
dataGridView2.DataSource = tb2;
reader2.Close();
conn.Close();
}
很显然,这样的话,就会发生两次的服务器往返。(两次批处理的过程)
使用DataReader做多结果集查询:一次性读取两个表格的数据
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString + ";MultipleActiveResultSets=true"))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT CustomerID FROM Customers;SELECT OrderID FROM Orders";
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
listBox1.Items.Add(reader[0].ToString());
}
while (reader.NextResult())
{
while (reader.Read())
{
listBox2.Items.Add(reader[0].ToString());
}
}
reader.Close();
conn.Close();
}
需要特别注意的是,因为DataReader是一个只向前,只读的游标集。所以如果它的结果集有超过一个,需要通过NextResult方法进行移动。同时,还需要启用MARS:多活动结果集 的支持。
如果换成是DataSet的方式,就无需这么麻烦,因为DataSet天生就是支持多个表格,在用DataAdatper的Fill方法填充数据的时候,它会自动地建立多个表格在DataSet里面。
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT CustomerID FROM Customers;SELECT OrderID FROM Orders";
conn.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
adapter.Fill(ds);
this.listBox1.DataSource = ds.Tables[0];
listBox1.DisplayMember = "CustomerID";
this.dataGridView2.DataSource = ds.Tables[1];
conn.Close();
}