【问题标题】:Dynamic hints in OracleOracle 中的动态提示
【发布时间】:2019-03-29 10:52:49
【问题描述】:

我正在研究是否可以在 Oracle 中使用动态提示。我们的系统适用于具有不同数据量的大量客户,因此我们希望为每个客户提供个性化查询。

我想这样做:

PROCEDURE PROCESS_STEP_1 (p_cust_id NUMBER)
IS
  v_hint_value NUMBER;
BEGIN
  -- Select correct value from param table
  SELECT value INTO v_hint_value
    FROM param_table
    WHERE cust_id = p_cust_id
      AND process_name = 'PROCESS_STEP_1';

  INSERT INTO result_table  
  SELECT /*+ PARALLEL v_hint_value */ * FROM etc.

END;

我知道可以通过动态查询来做到这一点。我们有很多,但由于可读性差和其他问题(这些 SQL 相当复杂)而不得不放弃它们。

您知道如何实现这样的事情吗?谢谢!

【问题讨论】:

    标签: oracle hints


    【解决方案1】:

    好的,我将从完全否定这种方法开始。我编写了很多高性能的 SQL 应用程序并且很少使用提示。您似乎在谈论一个大量提示的应用程序,其中提示因安装而异,这一事实是一个很大的危险信号。我建议您尝试删除这些提示并解决潜在的应用程序设计问题。

    总而言之,Oracle 具有 SQL 翻译功能。它旨在让您从为非 Oracle 数据库编写的应用程序中转换 SQL,但它也可以达到您的目的。您要做的是在 Oracle 解析之前使用此功能“翻译”任何入站 SQL 语句中的提示。

    下面是示例代码,用于说明概念并帮助您入门。再说一遍——我不推荐这个,但 SO 是一个回答的地方,而不是讲课的地方,所以这里是......

    第 1 步 -- 确保您有执行此操作的权限

    -- GRANT CREATE ANY SQL TRANSLATION PROFILE TO yourapplication
    -- GRANT TRANSLATE ANY SQL TO yourapplication
    -- GRANT USE ANY SQL TRANSLATION PROFLE TO yourapplication
    -- GRANT EXECUTE ON SYS.DBMS_SQL_TRANSLATOR TO yourapplication
    

    创建一个表来存储提示翻译

    这里的想法是您在应用程序中嵌入提示,例如“/+HINT12345/”,并且您将在每个客户站点以不同的方式填充此表。您显然可以比这更复杂。

    CREATE TABLE myapp_hint_translations ( hint_id VARCHAR2(80), hint_text VARCHAR2(800) );
    
    INSERT INTO myapp_hint_translations VALUES ( '/*+HINT12345*/','/*+PARALLEL(4)*/');
    
    COMMIT;
    

    创建一个 PL/SQL 包来执行提示转换

    您必须使用给定的过程名称和参数。他们需要 我们将使用的 DBMS_SQL_TRANSLATOR 包。

    CREATE OR REPLACE PACKAGE myapp_hint_translator IS
      PROCEDURE translate_sql( sql_text IN CLOB, 
                               translated_text OUT CLOB );
    
      PROCEDURE translate_error( error_code IN BINARY_INTEGER,
                                 translated_code OUT BINARY_INTEGER,
                                 translated_sqlstate OUT VARCHAR2 );
    
    END myapp_hint_translator;
    /
    
    CREATE OR REPLACE PACKAGE BODY myapp_hint_translator IS
      PROCEDURE translate_sql( sql_text IN CLOB, 
                               translated_text OUT CLOB ) IS
      BEGIN
        <<hint_search>>
        FOR r IN ( SELECT hint_id, hint_text FROM myapp_hint_translations ) LOOP
          IF INSTR(sql_text, r.hint_id ) > 0 THEN
            translated_text := replace(sql_text,r.hint_id,r.hint_text);
            RETURN;
          END IF;
        END LOOP;
        -- No translation made
        translated_text := sql_text;
      END translate_sql;
    
      PROCEDURE translate_error( error_code IN BINARY_INTEGER,
                                 translated_code OUT BINARY_INTEGER,
                                 translated_sqlstate OUT VARCHAR2 ) IS
      BEGIN
        -- We are not using this feature
        NULL;
      END;
    
    END myapp_hint_translator;
    

    告诉 Oracle 开始使用我们的翻译器

    BEGIN
      dbms_sql_translator.create_profile(profile_name => 'MYAPP');
      dbms_sql_translator.set_attribute(profile_name => 'MYAPP',
                                        attribute_name => dbms_sql_translator.attr_translator,
                                        attribute_value => 'myappschema.myapp_hint_translator');
    END;
    
    ALTER SESSION SET SQL_TRANSLATION_PROFILE=MYAPP;
    
    ALTER SESSION SET EVENTS = '10601 trace name context forever, level 32';
    
    -- Test some of your application and verify hints are being translated
    

    【讨论】:

    • 感谢您提供信息丰富的帖子,我不知道此功能!但我担心它对我没有帮助 - 至少我不知道如何动态更改占位符以替换为提示,因为每次执行过程可能会有所不同。我更新了帖子以更好地说明我的用例。它不是很暗示的应用,我们只是想更好地控制并行度——我们现在有固定的度数,但是我们的 DBA 告诉我们,对于不同的处理客户,由于数据量的差异很大,不同的值会带来更好的性能。
    • 如果您可以通过提示修复它,您可以使用我发布的内容的变体来修复它。您可能需要以某种方式从库缓存中逐出 SQL 以使它们重新解析。再一次,这整个想法对我来说听起来很糟糕。
    • 有许多用于控制或限制并行度 (DOP) 的数据库级和会话级设置,或用于指示 Oracle 计算最佳 DOP 的“自动”度。那些不工作?您可能想发布一个单独的问题,专门针对您的查询动态调整 DOP,因为这与您关于动态更改提示的帖子非常不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-22
    • 1970-01-01
    • 1970-01-01
    • 2013-04-04
    • 2020-10-08
    • 2017-04-26
    相关资源
    最近更新 更多