当在TSQL或PLSQL之类的东西中编写数据库查询时,我们通常可以选择使用游标迭代行来完成任务,或者制作一个同时执行相同作业的单个SQL语句。

此外,我们可以选择简单地将大量数据拉回到我们的应用程序中,然后使用C#或Java或PHP或其他任何方式逐行处理。

为什么使用基于集合的查询更好? 这个选择背后的理论是什么? 什么是基于游标的解决方案及其关系等效的一个很好的例子?

===============>>#1 票数:18

我所知道的主要原因是引擎可以通过在多个线程上运行来优化基于集合的操作。 例如,考虑一个快速排序 - 您可以将列表中的列表分成多个“块”,并在每个线程中单独排序。 SQL引擎可以在一个基于集合的查询中使用大量数据执行类似的操作。

执行基于游标的操作时,引擎只能按顺序运行,操作必须是单线程的。

===============>>#2 票数:16

除了上面的“让DBMS完成工作”(这是一个很好的解决方案)之外,还有其他一些很好的理由将查询留在DBMS中:

  • 它(主观地)更容易阅读。 在稍后查看代码时,您是否愿意尝试使用循环和事物解析复杂的存储过程(或客户端代码),或者您更愿意查看简洁的SQL语句?
  • 它避免了网络往返。 为什么要将所有数据推送到客户端再推回更多? 如果你不需要,为什么要捣乱网络呢?
  • 这很浪费。 您的DBMS和应用服务器需要缓冲部分/全部数据才能对其进行处理。 如果你没有无限的记忆,你可能会把其他数据分页; 为什么要从内存中挖出可能重要的东西来缓冲一个大多无用的结果集?
  • 你为什么不呢? 您购买(或以其他方式使用)高度可靠,速度非常快的DBMS。 你为什么不用它?

===============>>#3 票数:15

基于集合的查询(通常)更快,因为:

  1. 他们有更多信息供查询优化器优化
  2. 他们可以从磁盘批量读取
  3. 回滚,事务日志等涉及的日志记录较少。
  4. 减少了锁定,从而减少了开销
  5. 基于集合的逻辑是RDBMS的重点,因此它们已经针对它进行了大量优化(通常以牺牲程序性能为代价)

然而,将数据拉出到中间层以处理它可能很有用,因为它消除了DB服务器的处理开销(这是最难扩展的,并且通常也在做其他事情)。 此外,您通常在中间层中没有相同的开销(或收益)。 诸如事务日志记录,内置锁定和阻塞等等 - 有时这些是必要且有用的,有时它们只是浪费资源。

一个简单的游标,带有程序逻辑和基于集合的示例(T-SQL),它将根据电话交换分配区号:

--Cursor
DECLARE @phoneNumber char(7)
DECLARE c CURSOR LOCAL FAST_FORWARD FOR
   SELECT PhoneNumber FROM Customer WHERE AreaCode IS NULL
OPEN c
FETCH NEXT FROM c INTO @phoneNumber
WHILE @@FETCH_STATUS = 0 BEGIN
   DECLARE @exchange char(3), @areaCode char(3)
   SELECT @exchange = LEFT(@phoneNumber, 3)

   SELECT @areaCode = AreaCode 
   FROM AreaCode_Exchange 
   WHERE Exchange = @exchange

   IF @areaCode IS NOT NULL BEGIN
       UPDATE Customer SET AreaCode = @areaCode
       WHERE CURRENT OF c
   END
   FETCH NEXT FROM c INTO @phoneNumber
END
CLOSE c
DEALLOCATE c
END

--Set
UPDATE Customer SET
    AreaCode = AreaCode_Exchange.AreaCode
FROM Customer
JOIN AreaCode_Exchange ON
    LEFT(Customer.PhoneNumber, 3) = AreaCode_Exchange.Exchange
WHERE
    Customer.AreaCode IS NULL

===============>>#4 票数:8

你想要一些现实生活中的例子。 我的公司有一个光标,花了40多分钟处理30,000条记录(有时我需要更新超过200,000条记录)。 没有光标需要45秒才能执行相同的任务。 在另一种情况下,我删除了一个光标,并将处理时间从24小时发送到不到一分钟。 一个是使用values子句而不是select的插入,另一个是使用变量而不是连接的更新。 一个好的经验法则是,如果它是插入,更新或删除,您应该寻找基于集合的方式来执行任务。

游标有它们的用途(或者代码首先不是它们的代码),但是在查询关系数据库时它们应该是非常罕见的(除了经过优化以使用它们的Oracle)。 它们可以更快的一个地方是根据前面记录的值(运行总计)进行计算。 甚至应该测试。

使用游标的另一个有限情况是进行一些批处理。 如果您尝试以基于集合的方式一次性执行太多操作,则可以将表锁定到其他用户。 如果你有一个真正大的集合,最好将它分解为较小的基于集合的插入,更新或删除,这些插入,更新或删除不会过长地保持锁定,然后使用游标运行集合。

游标的第三种用途是通过一组输入值运行系统存储过程。 这仅限于一般的小集合,没有人应该搞乱系统过程,这对管理员来说是可以接受的。 我建议不要对用户创建的存储过程执行相同的操作,以便处理大批量并重用代码。 编写一个基于集合的版本会更好,因为在大多数情况下,性能应该胜过代码重用。

===============>>#5 票数:3

我认为真正的答案就像编程中的所有方法一样,取决于哪一个更好。 通常,基于集合的语言将更有效,因为这是它的目的。 光标有两个优势:

  1. 您正在更新数据库中的大型数据集,其中锁定行不可接受(可能在生产时间内)。 基于集合的更新可以将表锁定几秒钟(或几分钟),其中光标(如果正确写入)不会。 光标可以蜿蜒穿过一次更新一行的行,您不必担心影响其他任何事情。

  2. 使用SQL的优点是,在大多数情况下,优化工作的大部分由数据库引擎处理。 使用企业级数据库引擎,设计人员已经花了很长的时间来确保系统在处理数据方面的效率。 缺点是SQL是一种基于集合的语言。 您必须能够定义一组数据才能使用它。 虽然这听起来很容易,但在某些情况下并非如此。 查询可能非常复杂,引擎中的内部优化器无法有效地创建执行路径,并猜测会发生什么......具有32个处理器的超级强大的盒子使用单个线程来执行查询,因为它不知道如何做其他事情,所以你浪费处理器时间在数据库服务器上,通常只有一个而不是多个应用程序服务器(所以回到原因1,你遇到资源争用与需要在数据库服务器上运行的其他东西)。 使用基于行的语言(C#,PHP,JAVA等),您可以更好地控制发生的事情。 您可以检索数据集并强制它以您希望的方式执行。 (将数据分开以在多个线程上运行等)。 大多数情况下,在数据库引擎上运行它仍然不会有效,因为它仍然必须访问引擎来更新行,但是当你必须做1000多次计算来更新一行时(并且假设你有一百万行),数据库服务器可能会出现问题。

===============>>#6 票数:1

我认为归结为使用数据库是为了使用而设计的。 关系数据库服务器是专门开发和优化的,以最好地响应设置逻辑中表达的问题。

从功能上讲,游标的惩罚因产品而异。 一些(大多数?)rdbmss至少部分地构建在isam引擎之上。 如果问题是合适的,并且胶合板足够薄,那么使用光标实际上可能同样有效。 但在尝试之前,就你的dbms品牌而言,这是你应该非常熟悉的事情之一。

===============>>#7 票数:1

如前所述,数据库针对集合操作进行了优化。 字面上,工程师坐下来调试/调整了该数据库很长一段时间。 你优化它们的可能性非常小。 如果你有一组可以使用的数据,如批处理磁盘读/写,缓存,多线程,你可以使用各种有趣的技巧。 此外,某些操作的开销成本很高,但如果您同时对一堆数据进行操作,则每个数据的成本很低。 如果您一次只处理一行,则很多这些方法和操作都不会发生。

例如,只需查看数据库加入的方式。 通过查看解释计划,您可以看到几种连接方式。 很可能使用光标在一个表中逐行进行,然后从另一个表中选择所需的值。 基本上它就像一个嵌套循环,只是没有循环的紧密性(很可能编译成机器语言和超级优化)。 SQL Server本身有很多种加入方式。 如果对行进行排序,它将使用某种类型的合并算法,如果一个表很小,它可以将一个表转换为哈希查找表,并通过从一个表执行O(1)查找到查找表来执行连接。 许多DBMS都有许多连接策略可以帮助您从游标中的一个表中查找值。

只需看看创建哈希查找表的示例。 如果要连接两个长度为n且长度为m的表,其中m是较小的表,则构建表可能是m个操作。 每次查找应该是恒定时间,因此这是n次操作。 所以基本上散列连接的效率大约是m(设置)+ n(查找)。 如果你自己做并假设没有查找/索引,那么对于n行中的每一行,你将不得不搜索m个记录(平均而言它等于m / 2个搜索)。 所以基本上操作级别从m + n(一次连接一堆记录)到m * n / 2(通过游标进行查找)。 操作也是简化。 根据游标类型,获取游标的每一行可能与从第一个表中执行另一行选择相同。

锁也杀了你。 如果你有一个表上的游标你正在锁定行(在SQL服务器中,这对于static和forward_only游标来说不那么严重......但是我看到的大多数游标代码只是打开一个游标而没有指定任何这些选项)。 如果您在一组中执行操作,行仍将被锁定,但时间较短。 此外,优化器可以看到您正在做什么,并且它可能决定锁定整个表而不是一堆行或页面更有效。 但是如果你逐行去,优化器就不知道了。

另一件事是我听说在Oracle的情况下它是超级优化的游标操作,因此对于基于集合的操作而言,它与Oracle中的游标和SQL Server中的游标相差无几。 我不是Oracle专家,所以我不能肯定地说。 但不止一个Oracle人员告诉我,游标在Oracle中的效率更高。 所以,如果你为了Oracle牺牲了你的长子,你可能不必担心游标,请咨询当地高薪的Oracle DBA :)

===============>>#8 票数:0

简而言之,在大多数情况下,让数据库为您执行此操作会更快/更容易。

数据库的目的是以设定的格式存储/检索/操作数据,并且非常快。 您的VB.NET / ASP.NET代码可能远不如专用数据库引擎快。 利用这是明智的资源利用。

===============>>#9 票数:0

更喜欢在查询中完成工作的想法是数据库引擎可以通过重新构造来优化。 这也是为什么你想在你的查询上运行EXPLAIN,看看db 实际上在做什么。 (例如,利用索引,表格大小,有时甚至知道列中值的分布。)

也就是说,为了在实际的具体情况下获得良好的表现,你可能不得不屈服或违反规则。

哦,另一个原因可能是约束:如果在所有更新之后检查约束,则将一个唯一列增加一个可能没问题,但如果一个一个地完成,则会产生冲突。

===============>>#10 票数:0

基于set的操作在一个操作游标中完成与游标的行集一样多的操作

===============>>#11 票数:0

真正的答案是获得EF Codd的书籍之一,并了解关系代数 然后得到一本关于Big O符号的好书。 在IT近二十年后,恕我直言,这是现代MIS或CS学位的重大悲剧之一:很少有人真正研究计算。 你知道吗......“计算机”的“计算”部分? 结构化查询语言(及其所有超集)仅仅是关系代数的实际应用。 是的,RDBMS优化了内存管理和读/写,但对于过程语言也是如此。 在我读到它时,最初的问题不是关于IDE,软件,而是关于一种计算方法与另一种方法的效率。

即使快速熟悉Big O符号,也会开始阐明为什么在处理数据集时,迭代比声明语句更昂贵。

  ask by Eric Z Beard translate from so

未解决问题?本站智能推荐:

1回复

查询和游标

将在查询内部具有一个或多个子查询的结果导致SQL Server级别的游标。 换句话说,我没有显式使用游标,但是我有一个带有子查询的查询。 现在,为了处理该查询,SQL Server将在内部创建游标。
1回复

嵌套游标,多个结果集

我正在使用SQL Server存储过程来生成Excel报告。 基本上,报告中的每个“条目”都包含三个部分:对象,观察和点。 观察值引用了对象的主键,而这些点引用了观察值。 那就是零件之间的关系。 (对不起,如果我的术语不正确,我习惯于使用C#或Java编写,但仍在学习SQL。) 我
3回复

SQL查询而不是游标

我正在为一个假设的视频租赁商店创建一个数据库。 我需要做的是一个检查特定电影的可用性的过程(显然,该电影可以有多个副本)。 因此,我必须检查是否有可租用的副本,并获取副本的编号(因为以后会影响其他触发器。)。 我已经使用游标完成了所有操作,并且实际上效果很好,但是我需要(即“必须”)不使用
1回复

oracle中游标查询的Sqlcode

我有一个带查询的oracle游标 我需要光标中查询的SQLCODE。 我写了没有光标然后我可以得到SQLCODE但我需要SQLCODE与CURSOR。 在这里,我能够将'找到的数据'的SQLCODE设为0,将'找不到数据'设为100
1回复

具有动态SQL查询的游标

我正在尝试使用游标进行动态查询,我想为数据库中的每个表创建文件组,我有这个: 打印是因为这样我才能看到文件组的名称,但是我想添加以下内容:ALTER DATABASE AdventureWorks2012 ADD FILEGROUP FG_filegroupname 我知道我必须使
1回复

游标中的查询何时执行?

假设我有类似的东西: 如果我在打开游标之前从foo删除行,这些行是否仍然是游标结果的一部分? 查询SELECT * FROM foo在FOR row IN foo_cur ?
1回复

SQL查询:使用游标

我需要有关SQL Server和游标的一些说明: 我有一个名为Order的表: 我有另一个名为Storage的表: 对于每个OrderID,我想检查是否有足够的物品。 如果没有,我想返回一条错误消息。 游标怎么办呢? 嵌套游标是解决方案吗? 我的主要问题是了解如何获
2回复

Android游标查询计数

我正在开发一个小应用程序,它从数据库中读取数据并将其显示在一些自定义列表视图布局中。 我连接了所有的鸭子,但有一个问题,我无法围绕哪个问题在光标查询中执行计数 这是我的代码的一个简单示例 而查询本身 因此,最重要的问题是我如何预先形成每个制造商的总数或仅计算总数。
2回复

SQL查询中的游标

在Oracle中,它可能返回cursor的SQL查询中,使用cursor的关键字,像这样: 问题是: 有谁知道我在哪里可以找到这方面的文件? PortgreSQL(或任何其他开源DBMS)是否具有类似的功能?
1回复

带游标的plpgSQL函数查询

作为一个真正的学生,我在昨晚进行课程工作:)但是我尝试写了几天这个查询,但我不知道该怎么做。 这就是为什么我在这里写。 很抱歉,这可能是一个愚蠢的问题,但是我们所有人都在一段时间前就进行了很多错误和问题的第一步。 (对不起,我的英语,它现在很完美)。 顺便说一句,我的任务是: