提高 DAL 性能
我当前填充业务对象的方式是使用类似于下面的代码片段的方式。
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.CDRDatabase))
{
using (SqlCommand comm = new SqlCommand(SELECT, conn))
{
conn.Open();
using (SqlDataReader r = comm.ExecuteReader(CommandBehavior.CloseConnection))
{
while (r.Read())
{
Ailias ailias = PopulateFromReader(r);
tmpList.Add(ailias);
}
}
}
}
private static Ailias PopulateFromReader(IDataReader reader)
{
Ailias ailias = new Ailias();
if (!reader.IsDBNull(reader.GetOrdinal("AiliasId")))
{
ailias.AiliasId = reader.GetInt32(reader.GetOrdinal("AiliasId"));
}
if (!reader.IsDBNull(reader.GetOrdinal("TenantId")))
{
ailias.TenantId = reader.GetInt32(reader.GetOrdinal("TenantId"));
}
if (!reader.IsDBNull(reader.GetOrdinal("Name")))
{
ailias.Name = reader.GetString(reader.GetOrdinal("Name"));
}
if (!reader.IsDBNull(reader.GetOrdinal("Extention")))
{
ailias.Extention = reader.GetString(reader.GetOrdinal("Extention"));
}
return ailias;
}
有人对如何提高此类事情的性能有任何建议吗? 请记住,对于某些类型,PopulateFromReader 包含更多数据库查找,以便完全填充对象。
The way i currently populate business objects is using something similar to the snippet below.
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.CDRDatabase))
{
using (SqlCommand comm = new SqlCommand(SELECT, conn))
{
conn.Open();
using (SqlDataReader r = comm.ExecuteReader(CommandBehavior.CloseConnection))
{
while (r.Read())
{
Ailias ailias = PopulateFromReader(r);
tmpList.Add(ailias);
}
}
}
}
private static Ailias PopulateFromReader(IDataReader reader)
{
Ailias ailias = new Ailias();
if (!reader.IsDBNull(reader.GetOrdinal("AiliasId")))
{
ailias.AiliasId = reader.GetInt32(reader.GetOrdinal("AiliasId"));
}
if (!reader.IsDBNull(reader.GetOrdinal("TenantId")))
{
ailias.TenantId = reader.GetInt32(reader.GetOrdinal("TenantId"));
}
if (!reader.IsDBNull(reader.GetOrdinal("Name")))
{
ailias.Name = reader.GetString(reader.GetOrdinal("Name"));
}
if (!reader.IsDBNull(reader.GetOrdinal("Extention")))
{
ailias.Extention = reader.GetString(reader.GetOrdinal("Extention"));
}
return ailias;
}
Does anyone have any suggestions of how to improve performance on something like this? Bear in mind that PopulateFromReader, for some types, contains more database look-ups in order to populate the object fully.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
一个明显的变化是替换这种声明:
ailias.AiliasId = reader.GetInt32(reader.GetOrdinal("AiliasId"));
其中
constAiliasId 是一个常量,保存字段 AiliasId 的序号。
这避免了循环的每次迭代中的顺序查找。
One obvious change would be to replace this kind of statement:
ailias.AiliasId = reader.GetInt32(reader.GetOrdinal("AiliasId"));
with
where constAiliasId is a constant holding the ordinal of the field AiliasId.
This avoids the ordinal lookups in each iteration of the loop.
如果数据量很大,那么构建巨大列表的开销可能会成为瓶颈; 在这种情况下,使用流对象模型会更有效; 即,
使用代码(通过 foreach 等)只有一个对象需要处理(一次)。 如果他们想要获得一个列表,他们可以(使用新的
List(sequence)
,或者在.NET 3.5中:sequence.ToList()< /代码>)。
这涉及到更多的方法调用(每个序列项额外的
MoveNext()
/Current
,隐藏在foreach
后面),但您永远不会当您有进程外数据(例如来自数据库的数据)时请注意这一点。If the data volume is high, then it can happen that the overhead of building a huge list can be a bottleneck; in which case, it can be more efficient to use a streaming object model; i.e.
The consuming code (via
foreach
etc) then only has a single object to deal with (at a time). If they want to get a list, they can (with newList<SomeType>(sequence)
, or in .NET 3.5:sequence.ToList()
).This involves a few more method calls (an additional
MoveNext()
/Current
per sequence item, hidden behind theforeach
), but you will never notice this when you have out-of-process data such as from a database.您的代码看起来与我们的许多业务对象加载函数几乎相同。 当我们怀疑 DAL 性能问题时,我们会检查一些事情。
我们跳到数据库多少次? 有什么方法可以减少连接频率并通过使用多个结果集带回更大的数据块(我们使用存储过程)。因此,父对象将自己获取所有数据,而不是每个子对象加载自己的数据和它的孩子。 您可能会遇到脆弱的 SQL(需要匹配的排序顺序等)和棘手的循环来遍历 DataReader,但我们发现它比多次数据库访问更优化。
启动数据包嗅探器/网络监视器以准确查看通过线路传输的数据量。 您可能会惊讶地发现某些结果集有多大。 如果是,那么您可能会考虑解决该问题的其他方法。 就像延迟/延迟加载一些子数据一样。
确保您正在使用您要求的所有结果。 例如,从 SELECT * FROM(返回 30 个字段)改为简单的 SELECT Id, Name FROM(如果这就是您所需要的)可能会产生很大的差异。
Your code looks almost identical to a lot of our business object loading functions. When we suspect DAL performance issues, we take a look at a few things things.
How many times are we hopping out to the DB? Is there any way we can connect less often and bring back larger chunks of data via the use of multiple result sets (we use stored procedures.) So, instead of each child object loading its own data, the parent will fetch all data for itself and its children. You can run into fragile SQL (sort orders that need to match, etc) and tricky loops to walk over the DataReaders, but we have found it to be more optimal than multiple DB trips.
Fire up a packet sniffer/network monitor to see exactly how much data is being transmitted across the wire. You may be surprised to see how massive some of the result sets are. If they are, then you might think about alternate ways of approaching the issue. Like lazy/defer loading some child data.
Make sure that you are using all of the results you are asking for. For example, going from SELECT * FROM (with 30 fields being returned) to simply SELECT Id, Name FROM (if that is all you needed) could make a large difference.
AFAIK,这已经是最快的了。 也许缓慢是在 SQL 查询/服务器中。 或者别的地方。
AFAIK, that is as fast as it gets. Perhaps the slowness is in the SQL query/server. Or somewhere else.
真正的问题可能是您提到的多个、每个对象的查找。 您是否仔细观察过它们是否可以全部放入一个存储过程中?
It's likely the real problem is the multiple, per-object lookups that you mention. Have you looked closely to see if they can all be put into a single stored procedure?