【问题标题】:Using a temporary table in a DB2 function created for parallel processing..?在为并行处理创建的 DB2 函数中使用临时表..?
【发布时间】:2019-09-18 22:33:31
【问题描述】:

编辑:我在原始问题的末尾添加了更多内容。

[原问题]:

在 DB2 SQL 表函数中,声明的全局临时表的范围是否可以限制为函数的当前实例......?这是 DB2-for-i v7r3m0。

我正在计划一个用于分析字符数据的表函数。为此,该函数需要一个临时表来缓存信息,然后这些信息将以不同的方式重复循环,直到获得结果。我的第一个想法是使用声明的全局临时表,但是有“全局”这个词。

为了提高效率,我想用ALLOW PARALLELNOT FENCED 编写函数,但这两个选项似乎与DGTT 的性质相冲突。

另外,因为写入 DGTT 需要MODIFIES SQL DATA,所以我不确定是否有任何方法可以使用ALLOW PARALLEL,即使对函数进行了仔细设计。

documentation 让我有点困惑;也许我不明白什么?在开头的段落中说:

每个应用程序进程定义一个声明的临时表 同名的临时表有自己独特的描述。

然后在table-name 下显示:

如果声明的临时表,或者依赖的索引或视图 在已声明的临时表上已经存在同名的,一个 返回错误。

所以我想问一下:是否可以创建 DGTT 或任何其他类型的临时表,使其范围仅限于函数的当前实例..?

我可以随意为 DGTT 命名,但这会使代码复杂一些。理想情况下,我只想使用一个名称。

我的另一个想法是在 DGTT 中有一组由函数的输入参数填充的键列。然后该函数的所有实例可以共享一个 DGTT,但只能访问它们自己的行。

有人有什么建议吗..?

编辑:

好的,我已经连续工作了两天,终于创建了一个工作示例。 DGTT明显过剩;这些最初是 CTE,但我将它们全部转换为开发,以便在流程的每个步骤之后允许一个结果窗口。

最初的目的是成为一个带有一个输入参数和一个输出的标量函数,我认为它可以非常令人满意地成为一个没有输入参数的表函数。

我最终得到的结果非常有效,而且比我的前几次尝试快得多。事实上,我可以很容易地保持原样,但我会将 DGTT 转换回 CTE,看看效率是否有任何变化。可能我看不到任何变化,在这种情况下,没有 DGTT 会使我的整个 OP 变得无关紧要,哈哈。

话虽这么说,正如任何人都可能看到的那样,有几个机会可以创建循环,这将大大减少重复代码的数量和要处理的代码数量,并且还可以支持任意数量的单词......

-- THIS SCRIPT WAS NOT INTENDED TO BE THE FINAL PRODUCT, BUT MAY END UP CLOSE
-- DGTTs AND MULTIPLE RESULT WINDOWS WERE INTENDED TO EXAMININE EACH STEP
-- UNCOMMENT ANY OF THE SELECT STATEMENTS TO SEE WHAT'S GOING ON THERE 
-- THIS IS HARD-CODED TO PROCESS UP TO (9) WORDS
-- IF RE-WRITTEN WITH LOOPS, IT'D BE MORE COMPACT AND SUPPORT ANY NUMBER OF WORDS
DECLARE GLOBAL TEMPORARY TABLE SESSION.WORDS AS
    (   WITH    PASS1   AS (    SELECT      LPAD(TRIM(CHAR(BXUPCR)),14,'0')                     AS BXUPCR,
                                            UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,1,'i')))  AS W1,
                                            UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,2,'i')))  AS W2,
                                            UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,3,'i')))  AS W3,
                                            UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,4,'i')))  AS W4,
                                            UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,5,'i')))  AS W5,
                                            UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,6,'i')))  AS W6,
                                            UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,7,'i')))  AS W7,
                                            UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,8,'i')))  AS W8,
                                            UPPER(TRIM(REGEXP_SUBSTR(BXADDS,'[^ ]+',1,9,'i')))  AS W9
                                FROM        F_CERTOB.BEERXT AS BEERT
                                INNER JOIN  F_CERTOB.INVENT AS INVEN ON  BXITEM=IYITEM
                                WHERE       BXPACK > 999
                                AND         BXUPCR > 0
                                AND         BXUM    = 'CB'
                                AND         IYWHSE  = '1'
                                AND         IYSTAT IN ('A','B')
                            )
        --PASS #2: GROUP ITMES WITH IDENTICAL UPC & TEXT. THIS IS VERY FEW ITEMS OUT OF ALL.
        SELECT      BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9, COUNT(*) AS C
        FROM        PASS1
        GROUP BY    BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.WORDS ORDER BY 1,2,3,4,5,6,7,8,9,10 @

--NUMBER OF ITEMS PER UPC
DECLARE GLOBAL TEMPORARY TABLE SESSION.WCNT AS 
    (   SELECT      BXUPCR, COUNT(BXUPCR) AS UPC_COUNT
        FROM        SESSION.WORDS
        GROUP BY    BXUPCR
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.WCNT ORDER BY 1 @

--FUNNEL CERTAIN ITEMS FOR TESTING    ------------FOR DEV ONLY
--THIS CAN BE REMOVED AND PATCHED AROUND LATER
DECLARE GLOBAL TEMPORARY TABLE SESSION.FUNNEL AS 
    (   SELECT      A.BXUPCR, A.W1, A.W2, A.W3, A.W4, A.W5, A.W6, A.W7, A.W8, A.W9
        FROM        SESSION.WORDS AS A
        INNER JOIN  SESSION.WCNT  AS B ON A.BXUPCR=B.BXUPCR
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.FUNNEL ORDER BY 1 @

--GROUPS OF (1) WORD:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP1 AS 
    (   SELECT          BXUPCR, W1, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 1 AS THIS_GROUP
        FROM            SESSION.FUNNEL
        INNER JOIN      SESSION.WCNT USING(BXUPCR)
        WHERE           (W1) IS NOT NULL
        GROUP BY        BXUPCR, W1, UPC_COUNT
    HAVING          UPC_COUNT = COUNT(*)
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP1 ORDER BY 1 @

--GROUPS OF (2) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP2 AS 
    (   SELECT          BXUPCR, W1, W2, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 2 AS THIS_GROUP
        FROM            SESSION.FUNNEL
        INNER JOIN      SESSION.WCNT USING(BXUPCR)
        WHERE           (W1 || W2) IS NOT NULL
        GROUP BY        BXUPCR, W1, W2, UPC_COUNT
        HAVING          UPC_COUNT = COUNT(*)
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP2 ORDER BY 1 @

--GROUPS OF (3) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP3 AS 
    (   SELECT          BXUPCR, W1, W2, W3, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 3 AS THIS_GROUP
        FROM            SESSION.FUNNEL
        INNER JOIN      SESSION.WCNT USING(BXUPCR)
        WHERE           (W1 || W2 || W3) IS NOT NULL
        GROUP BY        BXUPCR, W1, W2, W3, UPC_COUNT
        HAVING          UPC_COUNT = COUNT(*)
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP3 ORDER BY 1 @

--GROUPS OF (4) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP4 AS 
    (   SELECT          BXUPCR, W1, W2, W3, W4, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 4 AS THIS_GROUP
        FROM            SESSION.FUNNEL
        INNER JOIN      SESSION.WCNT USING(BXUPCR)
        WHERE           (W1 || W2 || W3 || W4) IS NOT NULL
        GROUP BY        BXUPCR, W1, W2, W3, W4, UPC_COUNT
        HAVING          UPC_COUNT = COUNT(*)
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP4 ORDER BY 1 @

--GROUPS OF (5) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP5 AS 
    (   SELECT          BXUPCR, W1, W2, W3, W4, W5, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 5 AS THIS_GROUP
        FROM            SESSION.FUNNEL
        INNER JOIN      SESSION.WCNT USING(BXUPCR)
        WHERE           (W1 || W2 || W3 || W4 || W5) IS NOT NULL
        GROUP BY        BXUPCR, W1, W2, W3, W4, W5, UPC_COUNT
        HAVING          UPC_COUNT = COUNT(*)
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP5 ORDER BY 1 @

--GROUPS OF (6) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP6 AS 
    (   SELECT          BXUPCR, W1, W2, W3, W4, W5, W6, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 6 AS THIS_GROUP
        FROM            SESSION.FUNNEL
        INNER JOIN      SESSION.WCNT USING(BXUPCR)
        WHERE           (W1 || W2 || W3 || W4 || W5 || W6) IS NOT NULL
        GROUP BY        BXUPCR, W1, W2, W3, W4, W5, W6, UPC_COUNT
        HAVING          UPC_COUNT = COUNT(*)
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP6 ORDER BY 1 @

--GROUPS OF (7) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP7 AS 
    (   SELECT          BXUPCR, W1, W2, W3, W4, W5, W6, W7, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 7 AS THIS_GROUP
        FROM            SESSION.FUNNEL
        INNER JOIN      SESSION.WCNT USING(BXUPCR)
        WHERE           (W1 || W2 || W3 || W4 || W5 || W6 || W7) IS NOT NULL
        GROUP BY        BXUPCR, W1, W2, W3, W4, W5, W6, W7, UPC_COUNT
        HAVING          UPC_COUNT = COUNT(*)
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP7 ORDER BY 1 @

--GROUPS OF (8) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP8 AS 
    (   SELECT          BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 8 AS THIS_GROUP
        FROM            SESSION.FUNNEL
        INNER JOIN      SESSION.WCNT USING(BXUPCR)
        WHERE           (W1 || W2 || W3 || W4 || W5 || W6 || W7 || W8) IS NOT NULL
        GROUP BY        BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, UPC_COUNT
        HAVING          UPC_COUNT = COUNT(*)
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP8 ORDER BY 1 @

--GROUPS OF (9) WORDS:
DECLARE GLOBAL TEMPORARY TABLE SESSION.GRP9 AS 
    (   SELECT          BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9, UPC_COUNT, COUNT(*) AS UPC_GROUP_COUNT, 9 AS THIS_GROUP
        FROM            SESSION.FUNNEL
        INNER JOIN      SESSION.WCNT USING(BXUPCR)
        WHERE           (W1 || W2 || W3 || W4 || W5 || W6 || W7 || W8 || W9) IS NOT NULL
        GROUP BY        BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9, UPC_COUNT
        HAVING          UPC_COUNT = COUNT(*)
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.GRP9 ORDER BY 1 @

--MERGE EVERYTHING TOGETHER:
DECLARE GLOBAL TEMPORARY TABLE SESSION.UNIONX AS 
    (   SELECT      BXUPCR, W1 AS W1, '' AS W2, '' AS W3, '' AS W4, '' AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 1 AS WC
        FROM        SESSION.GRP1
        UNION
        SELECT      BXUPCR, W1 AS W1, W2 AS W2, '' AS W3, '' AS W4, '' AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 2 AS WC
        FROM        SESSION.GRP2
        UNION
        SELECT      BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, '' AS W4, '' AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 3 AS WC
        FROM        SESSION.GRP3
        UNION
        SELECT      BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, '' AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 4 AS WC
        FROM        SESSION.GRP4
        UNION
        SELECT      BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, '' AS W6, '' AS W7, '' AS W8, '' AS W9, 5 AS WC
        FROM        SESSION.GRP5
        UNION
        SELECT      BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, W6 AS W6, '' AS W7, '' AS W8, '' AS W9, 6 AS WC
        FROM        SESSION.GRP6
        UNION
        SELECT      BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, W6 AS W6, W7 AS W7, '' AS W8, '' AS W9, 7 AS WC
        FROM        SESSION.GRP7
        UNION
        SELECT      BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, W6 AS W6, W7 AS W7, W8 AS W8, '' AS W9, 8 AS WC
        FROM        SESSION.GRP8
        UNION
        SELECT      BXUPCR, W1 AS W1, W2 AS W2, W3 AS W3, W4 AS W4, W5 AS W5, W6 AS W6, W7 AS W7, W8 AS W8, W9 AS W9, 9 AS WC
        FROM        SESSION.GRP9
        GROUP BY    BXUPCR, W1, W2, W3, W4, W5, W6, W7, W8, W9
    )   WITH DATA WITH REPLACE @
--SELECT * FROM SESSION.UNIONX ORDER BY BXUPCR,W1,W2,W3,W4,W5,W6,W7,W8,W9 @

--FINAL RESULT:
DECLARE GLOBAL TEMPORARY TABLE SESSION.PICKER AS
    (   SELECT      BXUPCR, TRIM(W1 || ' ' || W2 || ' ' || W3 || ' ' || W4 || ' ' || W5 || ' ' || W6 || ' ' || W7 || ' ' || W8 || ' ' || W9) AS WORDS
        FROM        SESSION.UNIONX
        INNER JOIN  TABLE(  SELECT      BXUPCR, MAX(WC) AS WC
                            FROM        SESSION.UNIONX
                            GROUP BY    BXUPCR
                         )  AS TMP USING(BXUPCR, WC)
    )   WITH DATA WITH REPLACE @
SELECT * FROM SESSION.PICKER ORDER BY 1 @

【问题讨论】:

  • DGTT 可以作为正常插入/选择/等的一部分并行访问,就像任何其他表一样,因此任何语句都可以像往常一样按行并行化。因此,您还通常希望避免显式循环。我们可以更详细地了解您在这里要完成的工作吗?
  • 我在我的 OP 末尾添加了一个示例。
  • 你有一个问题 - 如果单词在同一 UPC 的两个实例中的顺序不同,它们将是不同的行。更一般地,您希望单词在相同数量的单词中具有相同的顺序。 BXADDS 代表什么?如果它是一个以空格分隔的值列表(违反正常形式不是很好),那么您最好的选择可能是定义一个表函数来吐出单词行。 (这在 LUW 上会更容易)。这几乎会自动让您获得无限的单词(并且旋转也会更容易一些)。
  • BXADDS 是作为人类可读标题的产品描述,例如“Mike's Harder Black Cherry Lemonade”。我们很擅长保持单词的正确顺序;我们必须,否则我们的 50 多名路线销售人员会冲我们大喊他们没有在产品列表中正确显示/排序。另外,您给了我另一个想法:如果单词很常见,但出现在不同的位置怎么办?比如“Mike's Harder Black Cherry Lemonade”和“Mike's Harder Watermelon Lemonade”..?常见的词是“Mike's Harder Lemonade”;中间的唯一词被跳过。
  • ...您实际上想要在这里完成什么?你需要这些信息是为了什么?如果您只想查询与某组词匹配的所有产品,那么您正在查看某种类型的全文搜索(DB2 for i 可能具有一些本机功能)。如果您试图为报告之类的内容找到通用元素,则无法避免拆分 (An example using a recursive CTE),但您可能可以执行一些操作,例如将拆分缓存到永久标签表中。

标签: db2 db2-400


【解决方案1】:

使用Declare global temporary table 创建的临时表在 QTEMP 中实现,每个作业是唯一的,而不是每个线程。也就是说,IBM i 在幕后执行缓存,并且可能比以往任何时候都做得更好,因此缓存数据的尝试通常只是浪费周期和内存缓存已经缓存的内容。我建议尝试在没有手动缓存的情况下执行您的流程,然后如果您需要在某处提高性能,请从索引开始。

SQL 是一种声明性语言,而不是过程性语言。这意味着最好的方法就是告诉它你想要的结果,然后让优化器决定如何得到它。成套思考,而不是过程。

【讨论】:

  • 我在我的 OP 末尾添加了一个示例。很有可能我已经能够直接开发 DGTT。
【解决方案2】:

我想问一下:DGTT或者任何其他类型的临时表可以吗 被创建,因此它的范围仅限于当前实例 函数..?

没有。

如果声明的临时表,或者依赖的索引或视图 在已声明的临时表上已经存在同名的,一个 返回错误。

您可以使用WITH REPLACE 子句避免此类错误。在这种情况下,相应的 DGTT 会被静默删除并重新创建。
因此,如果您不需要此 DGTT 的旧内容,只需在您的 DGTT 声明中使用此子句即可。

【讨论】:

  • 是的,我经常使用WITH REPLACE。但是,我担心并行运行的函数的多个实例相互冲突,并遍历同一 DGTT 中的不同数据。仅供参考 - 我在我的 OP 末尾添加了一个示例。
  • 如果您要多次使用与 DGTT 一起工作的函数in the same query,您显然应该牢记这一点,这样的函数不应该执行诸如删除/创建/修改任何同一 DGTT 的“非私有”部分。您可以避免这种对每个函数调用的唯一 DGTT 的干扰,或者为同一个 DGTT 使用一些“私钥”。
  • 我也是这么想的。我正在考虑为 DGTT 的每个实例生成一个随机 id,例如 GUID 或 UUID,然后将其用作 DGTT 的唯一名称(然后变为动态 SQL),或者对所有实例使用相同的 DGTT 进行转储他们的垃圾,但为生成的ID添加一个“实例”列,以便每个实例保持其垃圾直。越来越深...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 2021-01-23
  • 2021-12-13
  • 1970-01-01
  • 2012-04-23
相关资源
最近更新 更多