【问题标题】:Cursors vs duplicate code/logic游标与重复代码/逻辑
【发布时间】:2009-07-06 23:41:26
【问题描述】:

我听说使用游标不好,因为它们对 DBMS 来说“不自然”,而且它们的性能很差。
但是想象一下以下情况:我有一个存储过程,我需要为来自法国的每个客户调用这个存储过程(例如)。我有几个选项,例如使用游标,在一个查询中编写所有内容,并从客户端应用程序为每个客户调用存储过程。
如果我在一个查询中编写所有内容 - 它很可能会从已经存在的存储过程中复制代码/逻辑/整个查询。对我来说,这看起来像是一种“臭名昭著的方法”(如果您阅读了“重构”一书)。逻辑不再封装在一个地方。

你怎么看?

PS。欢迎提供任何描述游标为什么不好或不坏的文档的链接。

【问题讨论】:

    标签: database database-design stored-procedures cursors


    【解决方案1】:

    如果您致力于在数据库上以存储过程的形式拥有业务逻辑,那么游标就不错了。

    假设您有一个非常标准的客户端-服务器-数据库架构,将逻辑移出数据库并移入应用服务器可能是一个更好的主意。这有几个好处:

    1. 更好的可扩展性。添加应用服务器比添加数据库服务器更容易/更便宜。
    2. 集中业务逻辑。业务逻辑遍布各处的应用程序更难维护。

    【讨论】:

    • 我同意,但出于性能考虑,这并不总是可行的。
    【解决方案2】:

    还请记住,游标性能会因 RDBMS 而异。

    但是,我认为游标对于 SQL 数据库来说是不自然的(并且有一些专家会对此提出异议)。如果你考虑一下,游标可以被认为是一个迭代器(如果你真的想讨厌的话,甚至是一个指针)。虽然迭代器在过程语言中运行良好,但它们不适合 SQL 等声明性语言。

    现在,我还没有真正使用足够多的光标来同意或不同意这种想法。但我会说,当我想到它时,我真的想不出我编写的任何使用游标简化的查询(并不是说它们不存在)。

    【讨论】:

      【解决方案3】:

      有时光标是正确的工具。在其他时候,最好检索整个查询,并将其作为一个集合进行操作。

      SQL 内置了许多面向集合的操作。例如,UPDATE 可以对表中的一整组行进行操作。如果有 WHERE 子句,则这些行将被更新。更新可以使用上下文相关的子查询和 CASE 构造,在以看似不同的方式更新不同行方面提供很大的灵活性。

      对于刚刚开始熟悉 SQL 的程序员来说,将一个巨大的数据转换表达为单个 UPDATE 似乎是一项艰巨的任务。声明游标、遍历返回的行、将每一行视为一条记录并在处理时恢复为一条记录要容易得多。只要您对数据库的参与保持“精简”,这对您来说可能就足够了。

      但是,如果您希望构建工业级数据库,那么您应该学习如何根据行集而不是一次仅一行来操作数据。你会得到更好的表现。也许更重要的是,您会更清楚地了解底层业务规则和您编写的代码之间的关系。

      在设计良好的数据库中操作数据集要比在设计不佳的数据库中容易得多。如果您刚开始加快数据库设计的速度,同时也刚刚开始加快 SQL 查询的速度,那么您可能需要一位导师来为您的数据库设计提供建议。如果您不这样做,您可能很难学习面向集合的操作的强大功能和简单性。

      而且,您仍然会使用光标。

      【讨论】:

        【解决方案4】:

        根据您的存储过程的编写方式,如果您使用的是 SQL Server,您可能能够将其转换为函数。使用函数,您可以单独执行以下操作:

        SELECT uf_MyFunction(customer_id, customer_name, customer_address) FROM Customer
        

        将其应用于每个客户记录

        【讨论】:

          【解决方案5】:

          游标不一定是坏事,只是在大多数情况下,当你的直觉告诉你要使用它们时,有一种更高效的方式来使用声明式或基于集合的方法来做同样的事情。如果您发布 proc 的详细信息,我敢打赌,您会得到一些很好的建议,说明如何使用单个存储的 proc 调用和无光标来完成您需要的工作。

          【讨论】:

          • 我知道如何在没有光标的情况下执行此操作,但正如我所说,它会导致一些重复。
          • 坦率地说,我不明白为什么它会导致重复。创建一个参数化的存储过程,以便它可以根据输入返回单行或多行,然后在代码中的两个位置使用它。
          • 您能更好地解释一下您的意思吗?你可以编辑你的答案:)
          • 我仍然不明白为什么你认为你需要一个光标。如果你能回答这两个问题,我也许能提供更多帮助。 (1) 您正在考虑的游标是服务器端游标还是客户端游标,即循环在哪里实现? (2) 你想做什么让你认为你需要一个光标。简单地返回多行似乎并不意味着需要。也就是你需要重复调​​用的存储过程发生了什么?
          猜你喜欢
          • 2023-03-20
          • 2017-10-03
          • 2017-10-02
          • 2015-09-25
          • 1970-01-01
          • 2016-02-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多