Как написать следующий блок pl / sql без использования курсора? - PullRequest
0 голосов
/ 27 декабря 2011

Я написал курсор в блоке pl / sql. Этот блок отнимает много времени, если в нем больше записей. Как написать это без курсора или есть другой альтернативный способ, который сократит время? Есть ли альтернативный запрос для вставки в одну таблицу и удаления из другой таблицы с использованием одного запроса?

DECLARE
      MDLCursor SYS_REFCURSOR;
    BEGIN
      open MDLCursor for
        select dc.dest_id, dc.digits, dc.Effectivedate, dc.expirydate
          from DialCodes dc
         INNER JOIN MDL d
            ON dc.Dest_ID = d.Dest_ID
           AND d.PriceEntity = 1
          join sysmdl_calltypes s
            on s.call_type_id = v_CallType_ID
           and s.dest_id = dc.Dest_ID
           and s.call_type_id not in
               (select calltype_id from ignore_calltype_for_routing)
         order by length(dc.digits) desc, dc.digits desc;
      loop
        fetch MDLCursor
          into v_mdldest_id, v_mdldigits, v_mdlEffectiveDate, v_mdlExpDate;
        insert into tt_pendingcost_temp
          (Dest_ID,
           Digits,
           CCASDigits,
           Destination,
           tariff_id,
           NewCost,
           Effectivedate,
           ExpiryDate,
           previous,
           Currency)
          select v_mdldest_id,
                 Digits,
                 v_mdldigits,
                 Destination,
                 tariff_id,
                 NewCost,
                 Effectivedate,
                 ExpiryDate,
                 previous,
                 Currency
            FROM tt_PendingCost
           where substr(Digits, 1, 2) = substr(v_MDLDigits, 1, 2)
             and instr(Digits, v_MDLDigits) = 1
             and v_mdlEffectiveDate <= effectivedate
             and (v_mdlExpDate > effectivedate or v_mdlExpDate is null);
        if SQL%ROWCOUNT > 0 then
          delete FROM tt_PendingCost
           where substr(Digits, 1, 2) = substr(v_MDLDigits, 1, 2)
             and instr(Digits, v_MDLDigits) = 1
             and v_mdlEffectiveDate <= effectivedate
             and (v_mdlExpDate > effectivedate or v_mdlExpDate is null);
        end if;
        exit when MDLCursor%NOTFOUND;
      end loop;
      close MDLCursor;
    END;

1 Ответ

5 голосов
/ 27 декабря 2011

У меня нет ваших таблиц и ваших данных, поэтому я могу только догадываться о нескольких вещах, которые будут вас тормозить.

Во-первых, запрос, используемый в вашем курсоре, имеет предложение ORDER BYв этом.Если этот запрос возвращает много строк, Oracle должен извлечь их все и отсортировать все, прежде чем он сможет вернуть первую строку.Если этот запрос обычно возвращает много результатов, и вам не требуется его возвращать отсортированные результаты, вы можете обнаружить, что ваш блок PL / SQL немного ускоряется, если вы уроните ORDER BY.Таким образом, вы можете начать получать результаты из курсора без необходимости извлекать все результаты, сохранять их где-то и сначала сортировать.

Во-вторых, ниже приведено предложение WHERE, используемое в вашем INSERT INTO ... SELECT ...и DELETE FROM ... операторы:

    where substr(Digits, 1, 2) = substr(v_MDLDigits, 1, 2)
      and instr(Digits, v_MDLDigits) = 1
      and v_mdlEffectiveDate <= effectivedate
      and (v_mdlExpDate > effectivedate or v_mdlExpDate is null);

Я не понимаю, как Oracle может эффективно использовать индексы с любым из этих условий.Поэтому каждый раз приходится выполнять полное сканирование таблицы.

Последние два условия кажутся разумными, и с ними мало что можно сделать.Я хотел бы сосредоточиться на первых двух условиях, так как я думаю, что есть больше возможностей для их улучшения.

Вторым из четырех условий является

instr(Digits, v_MDLDigits) = 1

Это условие выполняется, если и толькоесли Digits начинается с содержимого v_MDLDigits.Лучшим способом написания этого будет

Digits LIKE v_MDLDigits || '%'

. Преимущество использования LIKE в этой ситуации вместо INSTR состоит в том, что Oracle может использовать индексы при использовании LIKE.Если у вас есть индекс по столбцу Digits, Oracle сможет использовать его с этим запросом.Затем Oracle сможет сосредоточиться на тех строках, которые начинаются с цифр в v_MDLDigits, вместо того, чтобы выполнять полное сканирование таблицы.

Первое из четырех условий:

substr(Digits, 1, 2) = substr(v_MDLDigits, 1, 2)

Если v_MDLDigits имеет длину не менее 2, а все записи в столбцах Digits также имеют длину не менее 2, то это условие является избыточным, поскольку оно подразумевается предыдущим, на которое мы смотрели.

Я не уверен, почему у вас было бы такое состояние.Единственная причина, по которой я могу подумать, почему у вас может быть это состояние, - это если у вас функциональный индекс на substr(Digits, 1, 2).Если нет, я бы соблазнился полностью удалить это substr условие.

Я не думаю, что курсор - это то, что заставляет эту процедуру выполняться медленно, и я не знаю ни одного известного утверждения, которое можно вставить водну таблицу и удалить из другой.Чтобы ускорить эту процедуру, я думаю, вам просто нужно немного настроить запросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...