哪种连接数据库的效率更高?

时间:2011-11-30 14:38:39

标签: c# asp.net sql-server coding-style data-access-layer

与同事有分歧,而我此时并不关心谁是对的,我更好奇哪个是更好的解决方案,以便我可以继续使用它。

我们有不同的方式来访问系统。

选项#1: 使用以下代码创建数据库。

using Microsoft.Practices.EnterpriseLibrary.Data;

namespace Ivans.Healthcare.CommercialAccess.Data
{
    public abstract class DataAccess : DataHelperBase
    {
        public const int commandTimeout = 7200;
        private static Database m_db = null;
        public StringBuilder Status {get; set;}

        public DataAccess()
        {
            this.Status = new StringBuilder();

            if (m_db == null)
            {
                bool bIfRunsOnWebService = false;
                try
                {
                    if (DynamicConfigurationManager.AppSettings["WebService"] != null)
                    {
                        bIfRunsOnWebService = true;
                    }
                }
                catch {}

                if (!bIfRunsOnWebService)
                {
                    m_db = DatabaseFactory.CreateDatabase(DataAccessResource.IDS_DB_ALIAS);
                }
                else
                {
                    m_db = CreateDatabase(DataAccessResource.IDS_WS_DB_ALIAS);
                }
            }
        }

然后每次需要调用存储过程时,该方法将包含如下内容:

public IEnumerable<InquiryServiceType> GetActive(bool is5010)
{

    Database db = getDB();
    DbCommand dbCmd = db.GetStoredProcCommand(DataAccessResource.IDS_SP_SEL_InquiryServiceTypeData_ListServiceTypes);
    db.AddInParameter(dbCmd, DataAccessResource.IDS_SP_SEL_InquiryServiceTypeData_ListServiceTypes_Is5010Request, DbType.Boolean, is5010);

    DataSet ds = new DataSet();
    db.LoadDataSet(dbCmd, ds, new string[] { DataAccessResource.IDS_TBL_InquiryServiceTypeData });

    return DataSetTranslator.TranslateInquiryServiceTypeDataSet(ds);
}

选项2

此选项更加模块化,并且正在尝试创建通用数据库方法。

    private Database currentDB;
private const int commandTimeout = 7200;

public DataAccess(Common.Enums.ConnectionString currentConnection)
{
    currentDB = DatabaseFactory.CreateDatabase(currentConnection.ToDescription());
}

public IEnumerable<T> SelectMany<T>(string spName, params Param[] parameters) where T : IDataPopulate<T>, new()
{
    var storedProcedure = CreateStoredProcedureCommand(spName);
    AddParameters(storedProcedure, parameters);

    IDataReader myReader = null;
    IList<T> listOfItems = new List<T>();

    try
    {
        myReader = currentDB.ExecuteReader(storedProcedure);
        if (myReader == null)
        {
            return listOfItems;
        }

        while (myReader.Read())
        {
            listOfItems.Add(new T().FillObject(myReader));
        }

        return listOfItems;
    }
    catch (Exception ex)
    {
        string message = string.Format("Error Message: {0}\r\nStored Procedure: {1}\r\n", ex.ToString(), spName);
        throw new Exception(message);
    }
    finally
    {
        DataAccessDisposal.DataReader(myReader);
        DataAccessDisposal.StoredProcedure(storedProcedure);
    }
}

然后调用数据库将如下所示:

public IEnumerable<InquiryServiceTypes> GetAll(int payerID)
{
    Param payerIdParam = new Param("@payerID", DbType.Int32, payerID);
    return dataAccess.SelectMany<InquiryServiceTypes>("dbo.proc_PayersInquiryServiceTypesSel", payerIdParam);
}

结论

在每个部分中肯定会错误地编码。我非常确定有一个中间地点是最有效的代码。

上面的代码有两点效率低下。首先是它如何连接到数据库。第二个是数据返回后,你如何处理它。我很乐意讨论两者,但我觉得第一点更重要的是这一点。

谢谢, ç

3 个答案:

答案 0 :(得分:5)

我会简单地说:有抽象已经做到这一点(做得很好)。如果您可以处理创建连接,例如,使用dapper-dot-net

return connection.Query<InquiryServiceTypes>(
        "dbo.proc_PayersInquiryServiceTypesSel",
        new { payerId }, commandType: CommandType.StoredProcedure);

将在高度缓存的IL中为您编写所有参数化和实现。无需编写复杂的Fill方法或填充方法,而且速度非常快(与手动编写所有ADO.NET读取器代码的性能相同,但没有无聊的代码和拼写错误的机会)。

手动编写所有这些Fill方法有效(对于开发人员来说)。

以上注意事项;匿名类型是定义参数,即它说“有一个名为payerId的int参数,其值与传入的值相同”。你也可以:

new { id = payerId, name = "abc", allData = true }

@id(int)与payerId@name(nvarchar)的值'abc'以及@allData(位)的值相加价值1


修改评论中的要点:

  • 连接池是正交的,因为只要您及时释放连接,默认情况下会自动完成(使用SQL服务器)
  • entlib在没有任何充分理由的情况下增加了IMO的开销。与entlib交谈的代码实际上与与原始ado.net交谈完全相同,除了更多的膨胀和间接。我会避免使用entlib,除非你真的使用它可以让你的生活更轻松
  • 加载数据集始终是开销; DataTable等很复杂 - 比加载POCO模型复杂得多。加载数据集只是,这样您就可以使用数据集加载对象模型效率低下,并在堆上创建需要收集的不必要的垃圾,并且还有很多步骤(适配器等) ,所有这些都需要时间
  • DataTable方法还要求完全读取表,而不是非缓冲假脱机(可以使用原始读取器和迭代器块);如果您的结果非常大,这可能会很重要
  • 中提到的两种方法,第二种是IMO更可取,但我喜欢界面;那是“关注点分离” - POCO的工作是代表域对象,而不是了解数据库
  • 如上所述,有类似于第二个选项的选项,更少工作实施/维护,并且不会引入SoC问题;我非常感兴趣地看着这个
  • 此类选项还可以为您解决更复杂的情况;多个网格;水平连接(进入子对象);等

答案 1 :(得分:0)

如果只需要只读访问权限来迭代返回的数据,那么使用datareader在性能和内存使用方面都会更有效。

有关数据访问技术的性能比较,请参阅http://msdn.microsoft.com/en-us/library/ms978388.aspx

建议您先看看使用Entity Framework,Massive或PetaPoco,因为使用其中一个框架可能会节省您的时间并使代码更具可读性/可维护性。

答案 2 :(得分:-1)

我个人认为,Dot网络代码即应用程序代码不得以任何方式与数据库耦合。原因是:

  1. 如果上面创建的方法是为SQL Server设计的,那么您将受到SQL Server的限制。您必须能够轻松切换存储空间。

  2. 如果在创建数据库时需要更多设置和限制,该怎么办?您必须发布另一个版本,因为您必须修改代码。

  3. 通用数据库方法在大多数情况下都会失败,并且很难调试。