安全性
考虑使用存储过程的最终原因是它们可用于增强安全性。
就管理用户对信息的访问而言,通过向用户授予对存储过程(而不是基础表)的访问权限,它们可以提供对特定数据的访问。您可以将存储过程看成是 SQL Server 视图(如果您对它们熟悉的话),除非存储过程接受用户的输入以动态更改显示的数据。
存储过程还可以帮助您解决代码安全问题。它们可以防止某些类型的 SQL 插入攻击 - 主要是一些使用运算符(如 AND 或 OR)将命令附加到有效输入参数值的攻击。在应用程序受到攻击时,存储过程还可以隐藏业务规则的实现。这对于将此类信息视为知识产权的公司非常重要。
另外,使用存储过程使您可以使用 ADO.NET 中提供的 SqlParameter 类指定存储过程参数的数据类型。这为验证用户提供的值类型(作为深层次防御性策略的一部分)提供了一个简单方法。在缩小可接受用户输入的范围方面,参数在内联查询中与在存储过程中一样有用。
使用存储过程增强安全性时值得注意的是,糟糕的安全性或编码做法仍然会使您受到攻击。对 SQL Server 角色创建和分配如果不加注意将导致人们访问到不应看到的数据。同时,如果认为使用存储过程便可防止所有 SQL 插入代码攻击(例如,将数据操作语言 (DML) 附加到输入参数),后果将是一样的。
另外,无论 T-SQL 位于代码还是位于存储过程中,使用参数进行数据类型验证都不是万无一失的。所有用户提供的数据(尤其是文本数据)在传递到数据库之前都应受到附加的验证。
存储过程对我是否适用?
或许适合吧。让我们概括一下它们的优点:
• |
通过降低网络流量提高性能 |
• |
提供单点维护 |
• |
抽象化业务规则,以确保一致性和安全性 |
• |
通过将某些形式的攻击降至最低,以增强安全性 |
• |
支持执行计划重复使用 |
如果您的环境允许利用存储过程提供的好处(如上所述),强烈建议使用它们。对于改进数据在环境中的处理方式而言,它们提供了一个很好的工具。另一方面,如果您的环境中存在可移植性、大量使用非 T-SQL 友好的进程或者不稳定的数据库架构等削弱这些优点的因素,则您可能要考虑其他方法。
另一个要注意的事项是机构内部所拥有的 T-SQL 专业人员的数量。您有足够的 T-SQL 知识吗?您愿意学习吗?或者,您有 DBA 或合适的人员帮您编写存储过程吗?掌握的 T-SQL 知识越多,存储过程就会越好,维护它们就会越容易。例如,T-SQL 主要用于基于集合的操作,而不是基于行的操作。依赖于光标(因为它们向您提示数据集)将导致性能降低。如果您不太了解 T-SQL,请将本文作为一次学习机会。无论您将它用在何处,本文介绍的知识都将改善您的代码。
因此,如果您认为存储过程会为应用程序增添特殊的效果,请继续阅读本文。我们将回顾一些简化存储过程使用的工具,并了解一些创建存储过程的最佳做法。
注意事项
如果要开始创建与应用程序一起使用的存储过程,应记住下面这些提示,以便两者正常运行并良好地配合工作。
使用 SET NOCOUNT ON
默认情况下,存储过程将返回过程中每个语句影响的行数。如果不需要在应用程序中使用该信息(大多数应用程序并不需要),请在存储过程中使用 SET NOCOUNT ON 语句以终止该行为。根据存储过程中包含的影响行的语句的数量,这将删除客户端和服务器之间的一个或多个往返过程。尽管这不是大问题,但它可以为高流量应用程序的性能产生负面影响。
create procedure test_MyStoredProc @param1 int
as
set nocount on
不要使用 sp_ prefix
sp_ prefix 是为系统存储过程保留的。数据库引擎将始终首先在主数据库中查找具有此前缀的存储过程。这意味着当引擎首先检查主数据库,然后检查存储过程实际所在的数据库时,将需要较长的时间才能完成检查过程。而且,如果碰巧存在一个名称相同的系统存储过程,则您的过程根本不会得到处理。
尽量少用可选参数
在频繁使用可选参数之前,请仔细考虑。通过执行额外的工作会很轻易地影响性能,而根据为任意指定执行输入的参数集合,这些工作时不需要的。您可以通过对每种可能的参数组合使用条件编码来解决此问题,但这相当费时并会增大出错的几率。
在可能的情况下使用 OUTPUT 参数
通过使用 OUTPUT 参数返回标量数据,可以略微提高速度并节省少量的处理功率。在应用程序需要返回单个值的情况下,请尝试此方法,而不要将结果集具体化。在适当的情况下,也可以使用 OUTPUT 参数返回光标,但是我们将在后续文章中介绍光标处理与基于集合的处理在理论上的分歧。
提供返回值
使用存储过程的返回值,将处理状态信息返回给进行调用的应用程序。在您的开发组中,将一组返回值及其含义标准化,并一致地使用这些值。这会使得处理调用应用程序中的错误更加容易,并向最终用户提供有关问题的有用信息。
首先使用 DDL,然后使用 DML
将 DML 语句放在数据定义语言 (DDL) 语句之后执行(此时 DML 将引用 DDL 修改的任意对象)时,SQL Server 将重新编译存储过程。出现这种情况,是由于为了给 DML 创建计划,SQL Server 需要考虑由 DDL 对该对象所作的更改。如果留意存储过程开头的所有 DDL,则它只需重新编译一次。如果将 DDL 和 DML 语句混合使用,则将强制存储过程多次进行重新编译,这将对性能造成负面影响。
始终使用注释
您可能不会始终维护此代码。但其他人员将来可能想要了解它的用途。'Nuff 曾经这样说。