l 总的考虑方向
1) 根据数据使用的方式来设计数据访问层
2) 缓存数据,避免不必要的操作
3) 使用服务帐户进行连接
4) 必要时连接,尽早释放
5) 关闭可关闭的资源
6) 减少往返
7) 仅返回需要的数据
8) 选择适当的事务类型
9) 使用存储过程
根据性能、可维护性、及实现难度来决定跨层数据传递的方式
2 具体实现
1)选用合适的Data Provider
应尽量使用专用的Data Provider,下面是一个性能比较表
由上图中可以看出SqlClient的速度是最快的,其主要原因是其他的数据提供者都经过的几个层次的转换,如下图
从图中可以看出,SqlClient直接访问DB Netlib而其他的数据提供者都经过了两层转换,因此,在设计多层应用的时候,并不是层次越多越好,而是应该在可扩展性与性能间取折中,增加层次是会降低性能的。
1) 数据库连接
i. 在方法中打开和关闭连接,即不要在类的构造函数中打开连接,在类的析构函数中关闭连接。
ii. 使用完连接明确地关闭。因为有连接池的支持,关闭连接只是将连接放回连接池,并不是真正销毁,不会带来性能开销,而会增加连接池中可用连接,提升性能。
iii. 当使用DataReaders时,指定CommandBehavior.CloseConnection
iv. 当使用Fill()与Updata()时,不要手动打开连接。因为DataAdapter会自动开启连接,但是如果是Command则需要手动开启。
v. 避免检查OleDbConnection的State属性,其性能开销相当大。
vi. 使用连接池。这种方法可以大幅度提高性能。默认的情况下,通过SqlClient连接数据库时,会使用连接池,另可以通过连接字符串来控制连接池的最大值,最小值,以及是否开启连接池。
2) SQL指令
i. 检查SQL的输入,并使用参数,直接使用字符连接容易遭受注入式攻击。
ii. 仅返回需要的行和例
iii. 对大的数据集使用分页功能
iv. 批次执行SQL,避免多次往返。
v. 如果没有数据返回则使用ExecuteNonQuery方法
vi. 当返回一个标量时,使用ExecuteScalar方法
vii. 不要在运行时间使用CommandBuilder,尽管很省事,但是开销很大。
3) 存储过程
i. 尽量使用存储过程
ii. 对于OleDbCommand,指令类型为CommandType.Text
iii. 使用SqlCommand,指令类型为CommandType.StoredProcedure
iv. 尽可能使用输出参数
v. 考虑在SQL Server中SET NOCOUNT ON,即关闭SQL Server的记数功能。
4) 事务
5) 使用参数
i. 在存储过程上使用参数
ii. 创建参数并指定类型
iii. 可将参数对象进行缓存
6) DataReader和DataSet
i. DataReader对象需要关闭
ii. 用DataReader时应,使用CommandBehavior.CloseConnection关闭连接
iii. DataReader应用在只读、只向前翻滚的数据访问场景
iv. 只想快速访问数据,不需要缓存功能应使用DataReader
DataSet在需要数据缓存,并在不同层间传递时使用。它可以存放多个结果集,可以在离线的情况下自由定位,查找数据。
总的来说,提高性能会降低可扩展性,以及维护难度,应在满足功能与非功能需求的情况下提高性能,另应在设计时就考虑性能,好的设计在性能上的提升比差的设计后期再修改要好得多。