【问题标题】:TSQL - Empty rows returned in a cursorTSQL - 游标中返回的空行
【发布时间】:2019-02-11 23:57:46
【问题描述】:

抱歉,这可能是一个非常愚蠢的问题——我正在使用一个游标,它连接了一个大约 697K 行的临时表和一个返回 78K 行的函数。 (我应该补充的是以前更糟糕的改进)。游标通过并匹配两个“表”中的两个值并更新第三个值。这需要6个小时左右。这是荒谬的。我们正在努力想办法提高效率。

感谢任何和所有建议。但我的询问是这样的——

它似乎返回如下所示的数据(在很多情况下为空信息)。我可以限制代码说哪里......数据不为空......但它不是它的返回 Null 它的空/不存在的行。我在想是否有办法排除这样的行,我们可能会限制我们的数据池。但我不完全知道这意味着什么。

declare @season int = 21

DECLARE @match varchar(55)
declare @perf_no int
declare @order_dt datetime

DECLARE   @price CURSOR
SET       @price = CURSOR FOR
SELECT    distinct match_criteria, perf_no, order_dt
FROM      #prices
OPEN      @price
FETCH NEXT
FROM      @price INTO @match, @perf_no, @order_dt
WHILE     @@FETCH_STATUS = 0
BEGIN

select  @match, @perf_no, @order_dt, x.price as 'amount'
from    #prices p
join    dbo.[LFT_GET_PRICES_Seasonal] (@season, @order_dt) x on p.perf_price_type = x.perf_price_type and p.zone_no = x.zone_no
where   match_criteria = @match and perf_no = @perf_no

FETCH NEXT
FROM @price INTO @match, @perf_no, @order_dt
END
CLOSE @price
DEALLOCATE @price

这是我们的函数返回的#prices 和# 示例。

价格

pkg_no  perf_no zone_no price_type  order_dt                    price   perf_price_type match_criteria
12      144     2707    1073        2018-09-03  00:00:00.000    NULL    115769          O5716788P1517Z2707
12      123     2707    1073        2018-09-03  00:00:00.000    NULL    115840          O5716788P1517Z2707
12      887     2707    1073        2018-09-03  00:00:00.000    NULL    115521          O5716788P1517Z2707

功能:

perf_price_type zone_no price   min_price   enabled editable_ind
115521          2678    12.00   12.00       Y       N
115521          2679    61.00   61.00       Y       N
115521          2680    41.00   41.00       Y       N

游标所做的是根据函数的价格更新#prices 表中的价格。 (我们使用光标仅将其限制为某些性能/有限标准)。但我愿意接受建议。以及如何改进这一点的建议。

【问题讨论】:

  • 第一个要问自己的问题是否需要光标?如果没有,请不要使用它。有几次您实际上需要使用游标。其次,很可能你不能有空白行,但没有看到你的代码我们无能为力
  • @Brad,我很想离开光标,但我认为在这种情况下我们可能需要它。我将使用代码(或尽可能多的代码)更新上述票证
  • @Cato 它是一个系统函数,我会仔细检查我(老实说根本不认为它已编入索引)——我只是尝试添加一个并收到此消息:无法在对象上创建索引'LFT_GET_PRICES_Seasonal' 因为该对象不是用户表或视图。
  • 不确定 LFT_GET_PRICES_Seasonal 的作用,但看起来您可以用#prices 表中的列替换变量?只需在一个查询中完成??此外,如果您得到空白行,请检查您的#prices 表的填充方式
  • 要确定导致空行的原因,您必须确定导致空行的特定数据。除非您提供最低限度的复制,否则不可能提供任何建议。 “这就是你的数据……或代码”——就是这样。

标签: sql-server tsql sql-update cursor no-data


【解决方案1】:

您写道,您想使用表值函数的结果更新#price 表。
您可以通过使用cross apply 而不是光标来做到这一点。 由于您没有发布正确的示例数据,因此我无法测试我的答案,但如果它满足您的需求,那么与光标相比,它的运行速度应该快如闪电。

DECLARE @season int = 21

UPDAET p
SET price = x.Price
FROM #Prices p
CROSS APPLY  
(
    SELECT * 
    FROM dbo.LFT_GET_PRICES_Seasonal(@season, order_dt) udf
    WHERE udf.perf_price_type = p.perf_price_type 
    AND udf.zone_no = p.zone_no
) x

SQL 最适合使用基于集合的方法而不是过程方法,这就是为什么您希望尽可能避免循环和游标,并且仅将它们用作最后​​的手段。

【讨论】:

  • 我喜欢避免使用游标和循环,而且我无法提供太多数据,因为它很难共享。但让我测试一下。谢谢。
  • 澄清一下,order_dt 来自交叉应用中的价格,是吗?作为参数。如果是这样,这很酷,我必须了解更多。
  • 是的,没错。不幸的是,apply 上的 official documentation 不是很详细,但它总是一个好的开始......
  • 看起来它成功了,我们将整个过程从 6 多小时缩短到了大约 30 多秒。谢谢你。我正在审查输出以确保逻辑正确,但到目前为止看起来不错。
  • @YelizavetaYR 好吧,我想说这是一个很好的改进......很高兴能提供帮助:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多