【问题标题】:Benefits of stored procedures vs. other forms of grabbing data from a database [duplicate]存储过程与从数据库中获取数据的其他形式相比的优势 [重复]
【发布时间】:2012-07-09 05:18:39
【问题描述】:

可能重复:
What are the pros and cons to keeping SQL in Stored Procs versus Code

只是好奇使用存储过程与从数据库获取数据的其他形式的优缺点。确保速度、准确性和安全性的首选方法是什么(我们不想要 sql 注入!)。

(我应该将此问题发布到另一个堆栈交换站点吗?)

【问题讨论】:

标签: sql sql-server stored-procedures


【解决方案1】:

根据所有数据库问题的答案“视情况而定”。但是,由于计划缓存,存储过程在速度方面肯定会有所帮助(尽管正确参数化的 SQL 也会从中受益)。准确性也不例外——不正确的查询无论是否在存储过程中都是不正确的。并且在安全性方面,它们可以提供一种有用的方式来限制用户的访问 - 因为您不需要让他们直接访问基础表 - 您可以只允许他们执行您想要的存储过程。然而,关于这个主题有很多问题,我建议你搜索一下并找出更多。

【讨论】:

  • 请注意:我很确定从 SQL 2005 开始,SP 和普通 SQL 查询都会被缓存。所以应该不再有任何性能差异。
  • 普通查询只要匹配完全,就会被缓存。参数化查询始终被缓存。
  • 所以SQL Server会制定新的执行计划并重新编译:select * from foo where id = 1 and select * from foo where id = 2?
  • 不一定,不。参数嗅探将允许那些被拾取(有时)。但是字符串参数的长度(直到最近 LINQ 大量产生)之类的差异可能会破坏这一点。我刚刚运行了两个查询,他们得到了不同的计划句柄。尝试 SELECT * FROM [sys].[dm_exec_query_stats] CROSS APPLY [sys].[dm_exec_sql_text]([sql_handle]) WHERE [text] LIKE 'select * from%'
  • 嗯,很有趣。我从未测试过不同的参数长度,但会记住这一点。在大多数情况下,我使用参数化查询,它似乎运行良好。
【解决方案2】:

Stackoverflow 上有几个关于这个问题的问题。我真的不认为你会在这里得到一个“正确”的答案,两者都可以很好地工作,而且都可以工作得非常糟糕。我认为如果您使用的是 Java,那么一般模式是使用像 Hibernate/JPA 这样的 ORM 框架。只要您正确使用该框架,就可以完全避免 SQL 注入攻击。我对 .Net 开发人员的经验是,他们更有可能使用存储过程支持的持久性,但这似乎比以前更加开放。 NHibernate 和其他 MS 技术似乎都越来越受欢迎。

我个人的观点是,一般来说,ORM 可以为您节省大量冗长编码的时间,因为它可以自动生成您在典型 CRUD 类型系统中使用的大部分 SQL。要获得这一点,您可能会放弃一点性能和一些灵活性。如果您的系统是中低容量(每天有成千上万个请求),那么 ORM 就可以满足您的需求。如果您开始每天处理数百万个请求,那么您可能需要一些更裸机的东西,例如直接 SQL 或存储过程。请注意,ORM 不会阻止您更直接地访问数据库,它通常不是您会使用的。

最后一点,我认为 ORM 持久性使应用程序更易于测试。如果您在大部分持久性中使用存储过程,那么您几乎肯定会开始在这些过程中获得一堆业务逻辑。要测试它们,您必须实际保存数据并与数据库交互,这会使测试变得缓慢而脆弱。使用 ORM 框架,您既可以避免大部分此类测试,也可以在您真正想要测试持久性时使用内存数据库。

见:

【讨论】:

    【解决方案3】:

    这在 Programmers SE 上可能会更好,但我会在这里回答。

    CRUD 存储过程曾经是,有时仍然是在 SQL DBMS 上进行数据持久性和检索的最佳实践。每个这样的 DBMS 都有存储过程,因此无论编码语言和 DBMS 是什么,实际上都可以保证您能够使用该解决方案,并且使用该解决方案的代码可以指向任何具有正确存储过程的 DB,它会以最少的代码更改工作(在不同的 DBMS 中调用 SP 时需要进行一些语法更改;这些通常被集成到语言的库支持中以访问特定 DBMS 上的 SP)。也许最大的优势是集中访问表数据;您可以像 Fort Knox 一样锁定表本身,并根据需要将 SP 的访问权限分配给更有限的用户帐户。

    但是,它们有一些缺点。首先,SP 很难进行 TDD,因为这些工具实际上并不存在于数据库 IDE 中;您必须在执行 SP 的其他代码中创建测试(因此测试必须使用预期的测试数据设置数据库)。从技术角度来看,这样的测试不是也不可能是“单元测试”,它是对小而窄的功能区域的小而窄的测试,没有副作用(例如读/写文件系统)。此外,SP 是在对功能进行所需更改时必须更改的另一层。向查询结果添加新字段需要更改表、检索源代码、和 SP。添加新方法来搜索特定类型的记录需要创建和测试语句,然后封装在 SP 中,并在 DAO 上创建相应的方法。

    可用的新最佳实践 IMO 是一个称为对象关系映射器或 ORM 的库。 ORM 抽象了实际的数据层,因此您需要的是代码对象本身,并且您根据这些对象的属性而不是表数据来查询它们。这些查询几乎总是代码可配置的,并根据您在对象模型和数据模型之间定义的一个或多个“映射”转换为 DBMS 的 SQL 风格(类型 A 的对象作为记录保存在表 B 中,此属性 C 写入字段 D)。

    优点是代码更灵活,实际上以这些代码对象的形式查找数据。查询的条件通常可以在代码中自定义;如果需要具有不同 WHERE 子句的新查询,您只需编写查询,ORM 会将其转换为新的 SQL 语句。因为 ORM 是唯一实际使用 SQL 的地方(并且大多数 ORM 使用系统存储的过程来执行可用的参数化查询字符串)注入攻击几乎是不可能的。最后,根据语言和 ORM,可以对查询进行编译器检查;在 .NET 中,提供了一个名为 Linq 的库,它提供了一种类似 SQL 的关键字语法,然后将其转换为方法调用,并提供给“查询提供程序”,该“查询提供程序”可以将这些方法调用转换为数据存储的本机查询语言。这也允许在代码中测试查询;您可以验证所使用的查询是否会在给定代表实际 DBMS 的内存对象集合的情况下产生所需的结果。

    ORM 的缺点是 ORM 库通常是特定于语言的; Hibernate 在 Java 中可用,在 .NET 中的 NHibernate(以及 L2E 和 L2SQL)以及一些类似的库(如 PHP 中的 Pork)都可用,但如果您使用较旧或更深奥的语言进行编码,则根本没有可用的类型。另一个是安全性变得有点棘手。大多数 ORM 需要直接访问表才能查询和更新它们。一些人会容忍被指向用于检索的视图和用于更新的 SP(允许分离视图/SP 和表安全性以及限制可检索字段的能力),但现在您正在混合两全其美;您仍然必须定义映射,但现在您在数据层中也有代码。克服这个问题的最简单方法是在其他地方实施您的安全性;强制应用程序使用 Web 服务获取数据,该服务使用 ORM 提供数据并具有特定的、有限的“前门”。此外,许多 ORM 在以某些方式使用时会出现一些性能问题;大多数设计用于“延迟加载”数据,在实际需要数据的那一刻而不是之前检索数据,当您不需要您要求的每条记录时,这会提高前期性能。但是,当您确实需要您要求的每条记录时,这会产生额外的往返行程。您必须以特定方式构建查询,以绕过这种预期的用例行为。

    哪个更好?你必须做出决定。我现在可以告诉你,使用 ORM 比 SP 更容易设置和正常工作,并且更容易对模式和查询进行更改(并限制范围)。在现代开发公司中,首要任务是使其首先工作,然后使其表现良好和/或防止入侵,这是一个巨大的优势。在大多数情况下,您认为安全是一个问题,其实不是,当安全确实是一个问题时,将解决方案放在 DB 层通常是错误的,因为 DBMS 是最后一行防御入侵;如果必须依靠 DBMS 本身来阻止不想要的事情发生,那么在它上面的许多软件和固件层中,您都没有这样做(甚至鼓励它发生)。

    【讨论】:

      猜你喜欢
      • 2011-06-12
      • 1970-01-01
      • 2011-06-08
      • 2013-08-01
      • 2021-08-14
      • 2010-09-09
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      相关资源
      最近更新 更多