我的问题是关于SQL连接状态,负载等,基于以下代码:
public IEnumberable<MyType> GetMyTypeObjects()
{
string cmdTxt = "select * from MyObjectTable";
using(SqlConnection conn = new SqlConnection(connString))
{
using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
{
conn.Open();
using(SqlDataReader reader = cmd.ExecuteReader())
{
while(reader.Read())
{
yield return Mapper.MapTo<MyType>(reader);
}
}
}
}
yield break;
}
如果有许多进程在IEnumerable对象的迭代之间运行类似的代码并且执行时间很长,我可以看到这可能是一个问题,因为连接将打开更长时间等等。但是,这似乎也有可能减少SQL服务器上的CPU使用率,因为它仅在使用IEnumerable对象时返回数据。它还降低了客户端上的内存使用量,因为客户端只需在其工作时加载一个MyType实例,而不是加载所有出现的MyType(通过遍历整个DataReader并返回List或其他内容)。
您是否有任何实例可以想到您不希望以这种方式使用IEnumerable,或者您认为它完全适合的任何实例?
这会给SQL服务器带来什么样的负载?
这是你在自己的代码中使用的东西(除非提及NHibernate,Subsonic等)吗?
答案 0 :(得分:6)
这不是我要遵循的模式。我不会像在锁定时那样担心服务器上的负载。遵循这种模式将数据检索过程集成到您的业务逻辑流程中,这似乎是一个全面解决问题的方法;你不知道在迭代方面会发生什么,而你正在插入它。一次性检索您的数据,然后在关闭阅读器后允许客户端代码对其进行枚举。
答案 1 :(得分:2)
我建议不要进行预优化。在许多情况下,将汇集连接。
我也不希望SQL Server上的负载有任何差异 - 查询已经编译完毕,并且将会运行。
答案 2 :(得分:2)
我不会使用它,因为它隐藏了正在发生的事情,并且可能在没有适当处置的情况下留下数据库连接。
当您读取了最后一条记录后,将关闭连接对象,如果在此之前停止读取,则不会处理连接对象。例如,如果您知道结果中总是有10条记录,并且只有一个循环从枚举器中读取这10条记录而没有使第11条读取调用超出最后一项,则连接未正确关闭。此外,如果您只想使用部分结果,则无法在不读取其余记录的情况下关闭连接。
即使您正确使用它们,即使是枚举器的内置扩展也可能导致这种情况:
foreach (MyType item in GetMyTypeObjects().Take(10)) {
...
}
答案 3 :(得分:1)
我担心的是你会把自己完全置于客户代码的怜悯之下。
您已经提到调用代码可能会使连接打开的时间超过严格必要的时间,但也有可能永远不会允许关闭/处置对象。
只要客户端代码使用foreach
,using
等或明确调用枚举器的Dispose
方法,那么您就可以了,但没有什么可以阻止它做这样的事情:
var e = GetMyTypeObjects().GetEnumerator();
e.MoveNext(); // open the connection etc
// forget about the enumerator and go away and do something else
// now the reader, command and connection won't be closed/disposed
// until the GC kicks in and calls their finalisers