помогите ускорить курсорчик

Vitosik
Дата: 25.11.2009 06:08:40
Есть такой курсор поиска зоны с самым длинным кодом для тарификации звонка по входным данным: номеру куда звонок ушел и времени для поиска подходящей зоны

cursor zone(bnumber varchar, starttime date) is
    select oz.id, oz.tariff
    from operator_zones oz
    where oz.code=substr(bnumber,1,length(oz.code))
    and oz.start_time<=starttime
    and (oz.end_time>starttime or oz.end_time is null)
    and oz.operator_id=v_operator
    order by length(code) desc;

Этот запрос занимает около 90% CPU при обсчете звонков
Можно ли его как-нить ускорить?
Вот эту конструкцию - oz.code=substr(bnumber,1,length(oz.code)) - можно переписать чтобы работал быстрее запрос?
SY
Дата: 25.11.2009 06:26:40
Vitosik
Вот эту конструкцию - oz.code=substr(bnumber,1,length(oz.code)) - можно переписать чтобы работал быстрее запрос?


Well, in general, post execution plan and table definition along with indexes. As a blind guess, try:

bnumber like oz.code || '%'

SY.
Vitosik
Дата: 25.11.2009 06:30:05
SY
Vitosik
Вот эту конструкцию - oz.code=substr(bnumber,1,length(oz.code)) - можно переписать чтобы работал быстрее запрос?


Well, in general, post execution plan and table definition along with indexes. As a blind guess, try:

bnumber like oz.code || '%'

SY.


пробовали и так - еще медленнее.... на несколько %
Вячеслав Любомудров
Дата: 25.11.2009 06:31:33
instr(bnumber, oz.code)=1
?
Vitosik
Дата: 25.11.2009 06:46:03
Вячеслав Любомудров
instr(bnumber, oz.code)=1
?

попробовал запустить - вроде быстрее пашет...
но...
Оптимизатор ругается:
Предикат INSTR(:B1,"OZ"."CODE")=1, используемый в строке с идентификатором 2 плана выполнения, содержит выражение индексированного столбца "CODE". Это выражение не позволяет оптимизатору эффективно использовать индексы для таблицы "BILADMIN"."OPERATOR_ZONES".


сейчас есть индекс по operator_id и code.
miksoft
Дата: 25.11.2009 07:10:13
Спросонья не вижу, что такое v_operator и откуда оно происходит?

Я бы заменил =substr(bnumber,1,length(oz.code)) на IN с перечислением всех начальных подстрок. Тогда индекс по oz.code или по паре полей (oz.code, oz.operator_id) имел бы смысл.
Vitosik
Дата: 25.11.2009 07:19:29
miksoft
Спросонья не вижу, что такое v_operator и откуда оно происходит?

Я бы заменил =substr(bnumber,1,length(oz.code)) на IN с перечислением всех начальных подстрок. Тогда индекс по oz.code или по паре полей (oz.code, oz.operator_id) имел бы смысл.


оператор задается в самом начале процедуры тарификации

bnumber in () или как?

а распаралелить выполнение этого курсора можно?
тарификация идет в for () loop
miksoft
Дата: 25.11.2009 07:29:23
Vitosik
bnumber in () или как?
Нет, oz.code IN ('123','1234',...) (самые короткие подстроки лучше исключить, насколько это логически возможно).

Еще лучше будет последовательно вызывать этот запрос с уменьшением длины подстроки и со строгим равенством, последовательно уменьшая длину подстроки, до тех пор пока не вернется какой-нибудь результат.
Т.е. примерно так:
select oz.id, oz.tariff
    from operator_zones oz
    where oz.code='79161234567'
    and oz.start_time<=starttime
    and (oz.end_time>starttime or oz.end_time is null)
    and oz.operator_id=v_operator

select oz.id, oz.tariff
    from operator_zones oz
    where oz.code='7916123456'
    and oz.start_time<=starttime
    and (oz.end_time>starttime or oz.end_time is null)
    and oz.operator_id=v_operator

select oz.id, oz.tariff
    from operator_zones oz
    where oz.code='791612345'
    and oz.start_time<=starttime
    and (oz.end_time>starttime or oz.end_time is null)
    and oz.operator_id=v_operator

...
Vitosik
Дата: 25.11.2009 07:33:07
miksoft
Vitosik
bnumber in () или как?
Нет, oz.code IN ('123','1234',...) (самые короткие подстроки лучше исключить, насколько это логически возможно).

Еще лучше будет последовательно вызывать этот запрос с уменьшением длины подстроки и со строгим равенством, последовательно уменьшая длину подстроки, до тех пор пока не вернется какой-нибудь результат.
Т.е. примерно так:
select oz.id, oz.tariff
    from operator_zones oz
    where oz.code='79161234567'
    and oz.start_time<=starttime
    and (oz.end_time>starttime or oz.end_time is null)
    and oz.operator_id=v_operator

select oz.id, oz.tariff
    from operator_zones oz
    where oz.code='7916123456'
    and oz.start_time<=starttime
    and (oz.end_time>starttime or oz.end_time is null)
    and oz.operator_id=v_operator

select oz.id, oz.tariff
    from operator_zones oz
    where oz.code='791612345'
    and oz.start_time<=starttime
    and (oz.end_time>starttime or oz.end_time is null)
    and oz.operator_id=v_operator

...


это должно реально шустрее выполняться? :)
Оптимизатор рекомендовал индекс operator_id, end_time с выигрышем в 73%...
попробовал - шустрее!
Elic
Дата: 25.11.2009 08:43:07
Vitosik
поиск зоны с самым длинным кодом для тарификации звонка
STFF Как можно выбрать максимум подходящую строку из таблицы?