提高DAL性能

3

我目前用类似下面代码片段的方式来填充业务对象。

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包含更多的数据库查找以完全填充对象。


你确实有性能问题吗?使用DataReader是处理这个问题最好、最快的方法——其他所有方法通常都基于DataReader。 - marc_s
我们在处理另一个表时遇到了问题,在 PopulateFromReader 方法中进行了多个查找。我正在尝试诊断问题所在,无论是数据访问层(DAL),服务器(不太可能),表结构还是带宽的问题。 - Ant Swift
5个回答

7

一种明显的改变是用以下语句替换这种语句:

ailias.AiliasId = reader.GetInt32(reader.GetOrdinal("AiliasId"));

替换为

ailias.AiliasId = reader.GetInt32(constAiliasId);

其中constAiliasId是一个常量,保存着字段AiliasId的序号。

这样可以避免在循环的每次迭代中进行序号查找。


不错的发现。许多人忘记了GetOrdinal需要额外的工作来获取正确的列。 - David Robbins
1
我的想法也是这样。在读取循环之外获取序数位置。 - RichardOD

5
如果数据量很大,那么构建一个巨大的列表的开销可能会成为瓶颈;这种情况下,使用流对象模型可能更加高效;即。
public IEnumerable<YourType> SomeMethod(...args...) {
    using(connection+reader) {
        while(reader.Read()) {
            YourType item = BuildObj(reader);
            yield return item;
        }
    }
}
< p >消费代码(通过foreach等)然后只有一个对象要处理(一次)。如果他们想要获取列表,他们可以使用新的List<SomeType>(sequence)或在.NET 3.5中使用sequence.ToList()

这涉及更多的方法调用(每个序列项额外的MoveNext()/Current,隐藏在foreach背后),但当您拥有来自数据库等外部数据时,您永远不会注意到这一点。


1

你的代码几乎与我们很多业务对象加载函数完全相同。当我们怀疑数据访问层性能问题时,我们会查看一些事情。

  1. 我们有多少次跳出到数据库?是否有任何方法可以连接更少,并通过使用多个结果集(我们使用存储过程)带回更大的数据块。因此,而不是每个子对象加载自己的数据,父对象将获取其自身和其子项的所有数据。您可能会遇到脆弱的SQL(需要匹配的排序等),以及遍历DataReaders的棘手循环,但我们发现这比多次DB访问更为优化。

  2. 启动数据包嗅探器/网络监视器,以查看穿越电线传输的确切数据量。您可能会惊讶地看到某些结果集有多么庞大。如果是这样,那么您可能需要考虑其他方法来解决问题。例如延迟/推迟加载某些子数据。

  3. 确保您正在使用您要请求的所有结果。例如,从SELECT * FROM(返回30个字段)转换为仅从SELECT Id,Name FROM(如果这是您所需的全部内容)。这可能会产生很大的差异。


0
据我所知,这已经是最快的了。也许缓慢的原因在于SQL查询/服务器,或者其他地方。

0

很可能真正的问题是你提到的每个对象多次查找。你是否仔细查看过它们是否都可以放入单个存储过程中?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接