WedX - журнал о программировании и компьютерных науках

Как заставить DB2 переоценивать план запроса при каждом выполнении?

У меня есть следующая хранимая процедура DB2, которая позволяет пользователю указать переменное количество параметров (указав NULL для параметров, которые они не хотят предоставлять), где каждый параметр может использоваться для фильтрации записей в предложении WHERE.

CREATE PROCEDURE XX.DUMMY(IN I_FIRST_NAME VARCHAR(32),
                            I_LAST_NAME VARCHAR(100),
                            I_COMPANY_NAME VARCHAR(100))
SPECIFIC XX.DUMMY
RESULT SETS 1
MODIFIES SQL DATA
NOT DETERMINISTIC
NULL CALL
LANGUAGE SQL EXTERNAL ACTION
INHERIT SPECIAL REGISTERS
BEGIN
    DECLARE RESULTS CURSOR WITH RETURN TO CLIENT FOR
        WITH RELEVANT_RECORDS (RECORD_ID) AS (
            SELECT RECORD_ID
            FROM XX.RECORDS R
            WHERE (I_FIRST_NAME IS NULL OR R.SEARCH_FIRST_NAME = I_FIRST_NAME)
            AND (I_LAST_NAME IS NULL OR R.SEARCH_LAST_NAME = I_LAST_NAME)
            AND (I_COMPANY_NAME IS NULL OR R.SEARCH_COMPANY_NAME = I_COMPANY_NAME)
            WITH UR
        )
        SELECT RR.RECORD_ID, RD.*
        FROM RELEVANT_RECORDS RR
        JOIN XX.RECORD_DETAILS RD ON RD.RECORD_ID = RR.RECORD_ID
        FOR READ ONLY WITH UR;
    OPEN RESULTS;
END
;

Насколько я понимаю, эта процедура будет работать очень плохо, потому что план запроса процедуры будет оцениваться только тогда, когда процедура связана (или запущена в первый раз?), где, если в более поздних запусках указаны разные комбинации параметров, исходный план запроса будет используется, что приводит к использованию неправильного плана/индекса (что делает процесс очень медленным).

Я читал, что SQL Server позволяет указать OPTION(RECOMPILE) в определении процедуры, чтобы указать серверу переоценивать план(ы) запроса для каждого выполнения процедуры, однако, поскольку я использую DB2, я ищу эквивалент DB2.

Есть ли способ в DB2, с помощью которого вы можете указать хранимой процедуре переоценивать свой план запроса при каждом выполнении? Должен ли я использовать что-то вроде SET CURRENT QUERY OPTIMIZATION внутри моей процедуры перед выполнением каких-либо операторов?


Ответы:


1

Использование динамического SQL в вашей подпрограмме (вместо статического SQL) — это один из способов обеспечить компиляцию запроса каждый раз (хотя он отличается от предыдущего экземпляра или не находится в кеше пакетов и т. д.).

В этом случае в вашей подпрограмме вы можете использовать EXECUTE IMMEDIATE для запроса, который вы динамически создаете внутри подпрограммы, или использовать PREPARE и EXECUTE. В обоих случаях полный запрос не существует до времени выполнения непосредственно перед выполнением. Таким образом, строка SQL, которую вы создаете, может каждый раз отличаться, включая (для выполнения) разное количество маркеров параметров (?) каждый раз и соответствующее количество параметров привязки. Сам SQL-запрос не является статическим — он может меняться каждый раз при запуске процедуры — в зависимости от (дезинфицированных) входных параметров хранимой процедуры.

Для статического SQL взгляните на хранимую процедуру SET_ROUTINE_OPTS с параметром REOPT ALWAYS, который необходимо выполнять во время сборки, или вы можете использовать переменную реестра DB2_SQLROUTINE_PREPOPTS поставлять эту инструкцию глобально (обычно это неразумно). Вы (или администратор базы данных) также можете организовать перепривязать статический пакет, соответствующий sproc, с ВСЕГДА REOPT.

11.03.2021
  • Можно ли использовать PREPARE и EXECUTE для указания подготовленного оператора с переменным числом параметров? Все примеры, которые я видел, передавались в виде статического списка параметров, которые не будут работать в моем случае (если только вы не поместите значения в массив и не передадите массив?). 11.03.2021
  • Вы уже поняли идею динамического SQL? 11.03.2021
  • Да, я думаю, что у меня правильная идея, я думаю, что сейчас моя проблема заключается в том, чтобы выяснить, как указать переменное количество параметров для инструкции EXECUTE. Похоже, я смогу использовать SQLDA для достижения этой цели, хотя я не уверен, что это лучший путь. 11.03.2021
  • Нет. Вы либо каждый раз подготавливаете/выполняете другой запрос, либо каждый раз выполняете_немедленно другой запрос. Не существует концепции переменного количества аргументов для выполнения одного конкретного запроса, вместо этого сам запрос (и соответствующее ему количество параметров) каждый раз отличается. 11.03.2021
  • Правильно, сам запрос каждый раз отличается, но выполняемый вами запрос будет иметь переменное количество маркеров запроса, где в операторе EXECUTE вам нужно будет указать ТОЛЬКО переменные хоста, которые имеют отношение к запросу. Это тот список переменных хоста, который я сейчас пытаюсь решить, где я думаю, что SQLDA (или массив) является ответом. Я не хочу определять объект массива, поэтому я думаю, что могу застрять с использованием SQLDA, если только не будет лучшего (или более простого) варианта. 12.03.2021

  • 2

    Вы можете попробовать DMBS_SQL.
    Он выглядит немного громоздким для такой простой цели, но работает.
    Окончательный оператор SELECT строится в зависимости от допустимости значений NULL для каждого параметра.
    br /> Локальные переменные XML используются для накопления выбранных строк, чтобы, наконец, вернуть их из SP. Вероятно, вы можете использовать для этого некоторую переменную [C|G]GTT или ARRAY вместо этих XML-переменных.

    --#SET TERMINATOR @
    
    -- Dynamic number of parameters demo
    CREATE OR REPLACE PROCEDURE TEST_DBMS_SQL
    (
      P_TABSCHEMA VARCHAR(128)
    , P_TABNAME   VARCHAR(128)
    )
    DYNAMIC RESULT SETS 1
    BEGIN
      DECLARE curid       INTEGER;
      DECLARE v_sql       VARCHAR(1000);
      DECLARE v_tabschema VARCHAR(128);
      DECLARE v_tabname   VARCHAR(128);
      DECLARE v_status    INTEGER;
      DECLARE v_doc       XML;
      DECLARE v_node      XML;
      
      DECLARE C1 CURSOR WITH RETURN FOR
      SELECT TABSCHEMA, TABNAME
      FROM XMLTABLE 
      (
        '$D/NODE' PASSING v_doc AS "D"
        COLUMNS
          TABSCHEMA VARCHAR(128) PATH 'TABSCHEMA'
        , TABNAME   VARCHAR(128) PATH 'TABNAME'
      );
      
      SET v_doc = XMLELEMENT(NAME "DOC");
      SET v_sql = 'SELECT TABSCHEMA, TABNAME FROM SYSCAT.TABLES WHERE 1=1';
      IF P_TABSCHEMA IS NOT NULL THEN
        SET v_sql = v_sql || ' AND TABSCHEMA = :p_tabschema'; 
      END IF;
      IF P_TABNAME IS NOT NULL THEN 
        SET v_sql = v_sql || ' AND TABNAME   = :p_tabname'; 
      END IF;
    
      CALL DBMS_SQL.OPEN_CURSOR(curid);
      CALL DBMS_SQL.PARSE(curid, v_sql, DBMS_SQL.native);
      
      IF P_TABSCHEMA IS NOT NULL THEN 
        CALL DBMS_SQL.BIND_VARIABLE_VARCHAR(curid, ':p_tabschema', P_TABSCHEMA);
      END IF;
      IF P_TABNAME IS NOT NULL THEN 
        CALL DBMS_SQL.BIND_VARIABLE_VARCHAR(curid, ':p_tabname', P_TABNAME);
      END IF;
    
      CALL DBMS_SQL.DEFINE_COLUMN_VARCHAR(curid, 1, v_tabschema, 128);
      CALL DBMS_SQL.DEFINE_COLUMN_VARCHAR(curid, 2, v_tabname, 128);
    
      CALL DBMS_SQL.EXECUTE(curid, v_status);
      --CALL DBMS_OUTPUT.PUT_LINE('Execute: ' || v_status);
      
      FETCH_LOOP: LOOP
      
        CALL DBMS_SQL.FETCH_ROWS(curid, v_status);
        IF v_status = 0 THEN LEAVE FETCH_LOOP; END IF;
        --CALL DBMS_OUTPUT.PUT_LINE('Fetch: ' || v_status);
        CALL DBMS_SQL.COLUMN_VALUE_VARCHAR(curid, 1, v_tabschema);
        CALL DBMS_SQL.COLUMN_VALUE_VARCHAR(curid, 2, v_tabname);
        --CALL DBMS_OUTPUT.PUT_LINE('TABSHEMA: ' || coalesce(v_tabschema, '*'));
        --CALL DBMS_OUTPUT.PUT_LINE('TABNAME: ' || coalesce(v_tabname, '*'));
        SET v_node = XMLELEMENT
        (
            NAME "NODE"
          , XMLELEMENT(NAME "TABSCHEMA", v_tabschema)
          , XMLELEMENT(NAME "TABNAME", v_tabname)
        );
      
        SET v_doc = XMLQUERY
        (
          'transform copy $mydoc := $doc modify do insert $node as last into $mydoc return $mydoc'
          passing v_doc as "doc", v_node as "node"
        );
      
      END LOOP FETCH_LOOP;
      
      --CALL DBMS_OUTPUT.PUT_LINE(XMLSERIALIZE(v_doc AS CLOB(10K)));
      CALL DBMS_SQL.CLOSE_CURSOR(curid);
      
      OPEN C1;
    END@  
    

    Использование:

    call test_dbms_sql(NULL, 'TABLES')@
    call test_dbms_sql('SYSCAT', 'TABLES')@
    call test_dbms_sql('SYSCAT', NULL)@
    call test_dbms_sql(NULL, NULL)@
    
    12.03.2021
    Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    © 2024 wedx.ru, WedX - журнал о программировании и компьютерных науках
    Для любых предложений по сайту: [email protected]