在 Oracle 中找到值后停止 SQL SELECT 语句的最佳方法

时间:2021-02-15 18:41:17

标签: sql oracle

以下查询返回 3 行:

  SELECT ffv.flex_value
    FROM fnd_flex_value_sets ffvs, fnd_flex_values ffv, fnd_flex_values_tl ffvtl
   WHERE     ffvs.flex_value_set_name = 'XXXXXXXX'
         AND ffv.flex_value_set_id = ffvs.flex_value_set_id
         AND ffv.flex_value_id = ffvtl.flex_value_id
         AND ffv.enabled_flag = 'Y'
         AND ffv.summary_flag <> 'Y'
         AND ffvtl.language = USERENV ('LANG')

只要我添加了下面的 EXISTS 子句,就会永远返回相同的 3 行或 1 或 2 行。我无法修改此函数或创建它的副本,因为它是一个云,我们没有任何选项来创建/修改这些函数。 存在子句中的下表大约有 159330 行

AND EXISTS
                 (SELECT 1
                    FROM gl_code_combinations gcc
                   WHERE     gcc.segment1 = ffv.flex_value
                         AND fnd_flex_xml_publisher_apis.process_kff_combination_1 (
                                 'FLEX_SECURE',
                                 'GL',
                                 'GL#',
                                 gcc.chart_of_accounts_id,
                                 NULL,
                                 gcc.code_combination_id,
                                 'ALL',
                                 'Y',
                                 'SECURITY') = 'Y')

是否有任何可能的最佳方法来提高 Oracle SQL 中此查询的性能?

2 个答案:

答案 0 :(得分:2)

正如@pmdba 上面指出的,WHERE 子句中的函数对性能来说是一个大问题。对组合数据集中的每一行都评估 EXISTS 条件,因此可以调用数十万次云函数。

如果您只想在主查询的结果集(3 行)上调用您的函数,您可以尝试几种技巧。

首先是将您的主查询移动到内联视图中,并将 WHERE 条件和函数放在它之外。这对我来说并不总是有效 - 有时优化器会重写这些查询以删除内联视图 - 但它通常会有所帮助。

select flex_value
from (
    SELECT ffv.flex_value
        FROM fnd_flex_value_sets ffvs, fnd_flex_values ffv, fnd_flex_values_tl ffvtl
       WHERE     ffvs.flex_value_set_name = 'XXXXXXXX'
             AND ffv.flex_value_set_id = ffvs.flex_value_set_id
             AND ffv.flex_value_id = ffvtl.flex_value_id
             AND ffv.enabled_flag = 'Y'
             AND ffv.summary_flag <> 'Y'
             AND ffvtl.language = USERENV ('LANG')
    ) ffv
where EXISTS (SELECT 1 from g1_code_combinations gcc ... )

第二种方法是将您的函数移动到 SELECT 子句中。 SELECT 子句是被评估的查询的最后一部分,因此对于返回的每一行,该函数只会被调用一次。在这种情况下,最多 3 次。

select flex_value
from (
    SELECT ffv.flex_value,
            fnd_flex_xml_publisher_apis.process_kff_combination_1 (
                             'FLEX_SECURE',
                             'GL',
                             'GL#',
                             gcc.chart_of_accounts_id,
                             NULL,
                             gcc.code_combination_id,
                             'ALL',
                             'Y',
                             'SECURITY') func_result
        FROM fnd_flex_value_sets ffvs
        JOIN fnd_flex_values ffv
            ON ffv.flex_value_set_id = ffvs.flex_value_set_id
        JOIN fnd_flex_values_tl ffvtl
            ON ffv.flex_value_id = ffvtl.flex_value_id
        JOIN gl_code_combinations gcc
            ON gcc.segment1 = ffv.flex_value
       WHERE     ffvs.flex_value_set_name = 'XXXXXXXX'
             AND ffv.enabled_flag = 'Y'
             AND ffv.summary_flag <> 'Y'
             AND ffvtl.language = USERENV ('LANG')
    ) v
where func_result = 'Y'

答案 1 :(得分:0)

向内联视图添加 ROWNUM 谓词以停止优化器转换并强制函数在最后运行,在内联视图的所有过滤完成后。

SELECT ...
(
    ...
    --Prevent optimizer transformations so that the function will run *after* all filtering.
    AND ROWNUM >= 1
)
WHERE fnd_flex_xml_publisher_apis.process_kff_combination_1(...) = 'Y'; 

简单地将查询重新编写为不同的顺序几乎不会改变执行计划。添加 ROWNUM 使 Oracle 认为这是一个 Top-N 报告查询,其中顺序很重要,这将阻止所有谓词推送、视图合并和其他转换。实现此目的的一种更正式的方法是使用优化器提示,但很难获得正确的提示。