SqlDataReader和元数据的内部工作

时间:2014-06-26 09:14:40

标签: c# .net sql-server

出于好奇和对更多洞察力的永恒渴望:)

这里有这个CLR存储过程,它通过以下代码将结果发送回客户端。 SqlMetaData的数组附加到SqlDataRecord。每个SqlDataRecord都获取通过管道发送给客户端的值。

SqlMetaData[] columns = new SqlMetaData[1];

columns[0] = new SqlMetaData("bool", SqlDbType.Bit);

SqlDataRecord record = new SqlDataRecord(columns);
SqlContext.Pipe.SendResultsStart(record);

foreach (bool b in bools)
{
     record.SetBoolean(0, b);

      SqlContext.Pipe.SendResultsRow(record);
}
SqlContext.Pipe.SendResultsEnd();

客户代码:

SqlCommand cmd = new SqlCommand("CLR_SPROC", connection)

SqlDataReader reader = cmd.ExecuteReader();

int b = reader.GetOrdinal("bool"); // b == 0 because it was added in index 0 in the SqlMetaData array

所以" bool"的顺序在第一个索引中首先找到它。有趣。

现在的问题是:

对于每个查询,SqlServer是否都在这样工作?我的意思是在执行查询时,查询解析器是否在最终选择中提取列名,从中构建一个SqlMetaData数组,将其附加到SqlDataRecord并通过流将其发回?

所以查询" SELECT a,b,c FROM table"

成为

SqlMetaData[] columns = new SqlMetaData[3];

columns[0] = new SqlMetaData("a", SqlDbType.Int);
columns[1] = new SqlMetaData("b", SqlDbType.Int);
columns[2] = new SqlMetaData("c", SqlDbType.Int);

 SqlDataRecord record = new SqlDataRecord(columns);
 SqlContext.Pipe.SendResultsStart(record);

foreach(...)
{
  record.SetInt32(0, a);
  record.SetInt32(1, b);
  record.SetInt32(2, c);
  SqlContext.Pipe.SendResultsRow(record);
}

1 个答案:

答案 0 :(得分:2)

SQL Server使用TDS协议(表格数据流)与客户端进行通信。 TDS是一种流协议,包括描述结果集的元数据,后跟结果集数据流。结果集中的记录包含相同的数字列,列名和数据类型,因此处理结果集所需的元数据只需要发送一次而不是附加到每个记录。

像SqlClient这样的客户端API将低级TDS结构暴露为更高级别的对象,如SqlMetaData,SqlDataRecord和SqlDataReader。虽然您可以直接针对客户端API而非TDS进行编码,但您可能会对TDS通信有一个粗略的了解,因为它提供了SQL Server如何在幕后工作的视图。您可以在http://msdn.microsoft.com/en-us/library/dd304523.aspx找到TDS协议的详细信息。