我有一个使用SqlDataReader读取数据并返回IEnumerable的方法,例如:
IEnumerable<string> LoadCustomers()
{
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return rdr.GetString(0);
}
}
}现在让我们假设我只需要最新的10个客户。我可以
LoadCustomers.Take(10)或将10作为参数传递给sql并使我的sql
SELECT TOP 10 FROM Customers ORDER BY CreationDate DESC根据this post,整个结果集将从server传输到客户端,即使数据中心只读取几行(只要连接打开)--我是否应该避免使用Take(10)方法,因为额外的数据无论如何都要传输给客户端,或者避免它是一个过早的优化(因为生成的返回代码将在读取10行之后关闭连接,然后数据传输无论如何都会停止)?
发布于 2016-07-29 10:48:59
由于优化是否“过早”是主观的,所以我选择将这个问题解释为“使用DataReader并在10行后停止读取与在查询中使用TOP(10)具有相同的性能特征吗?”
答案是否定的。将TOP(10)传递给服务器允许优化器调优读、内存授予、I/O缓冲区、锁定粒度和并行性,同时知道查询最多将返回10行(在本例中也是读取)。省略TOP意味着它必须为客户机将读取所有行的情况做好准备--不管您是否确实提前停止了。
不管读取与否,服务器都不会发送行。使用SqlDataReader拖动行在概念上是逐行操作:当您发出Reader.MoveNext时,您将从服务器获取下一行,并且只获取该行。但为了性能起见,在请求行之前会对行进行缓冲(无论是在服务器端,还是在网络缓冲区中)。因此,可以在第一次.MoveNext调用之后在缓冲区中检索100行,即使您只读取其中的10行。
关于开销,这并不是我最关心的问题,因为这些缓冲区最终都有固定的大小:无论有多少行,服务器都不会去缓冲结果集的所有行(这通常是非常低效的)。如果您只读取10行,那么如果查询运行完成,您的查询最终会返回1,000或1,000,000行,这在缓冲方面并不重要,而主要取决于查询计划。尽管如此,它确实增加了开销。
发布于 2016-07-27 10:09:57
您还可以使用分页Skip(0)并采取(10)更多的灵活性。
SQL SERVER 2012
SELECT name,
CreationDate
FROM customer
ORDER BY
CreationDate
OFFSET @skip ROWS
FETCH NEXT @take ROWS ONLY;SQL 2005至2008
SET @take = (@skip + @take)
;WITH customer_page_cte AS
(SELECT
name,
CreationDate,
ROW_NUMBER() OVER (ORDER BY CreationDate desc) AS RowNumber
FROM customer
)
SELECT name,
CreationDate
FROM customer_page_cte
WHERE RowNumber > @skip AND RowNumber <= @take使用SQL2012的C# -使用用于命令的存储过程:)
var command = @"SELECT name,
CreationDate
FROM customer
ORDER BY
CreationDate
OFFSET @skip ROWS
FETCH NEXT @take ROWS ONLY;";
using (var conn = new SqlConnection("Data Source=.;Initial Catalog=Stackoverflow;Integrated Security=True"))
{
conn.Open();
using (var cmd = new SqlCommand(command, conn))
{
cmd.Parameters.AddWithValue("skip", 0);
cmd.Parameters.AddWithValue("take", 10);
var reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader.GetString(0));
}
}
}https://stackoverflow.com/questions/38608926
复制相似问题