Отправляет email-рассылки с помощью сервиса Sendsay

Открыто о СУБД Oracle на русском

  Все выпуски  

Открыто о СУБД Oracle на русском : Оптимизация сложного запроса


Информационный Канал Subscribe.Ru

Выпуск 7

Оптимизация сложного запроса

Уважаемые подписчики! Этот выпуск посвящен одному из вопросов, на которые ответилв начале месяца Том Кайт на сайте asktom.oracle.com. Обещанные комментарии к сценарию, с помощью которого Том получает такие красивые приглашения в SQL*Plus, как и о самом SQL*Plus - в следующем выпуске.


Дядю Тома спросили об оптимизации запроса:

Как оптимизировать запрос с конструкцией where следующего вида

select * from document where (documentid=1234 and version number =1.1)
or (documnetid=1233 and versionnumber=1.2) or...

и так далее для примерно 1500 документов, 1500 условий or.

Этот запрос выполняется около 3,5 минут.

и он ответил

Надеюсь, на самом деле вы не указывали литералы в запросе -- одно это будет жестоким ударом по производительности. Во всех подобных запросах надо использовать связываемые переменные.

Я рекомендую не использовать кучу операторов OR или AND, а вместо этого сделать примерно так:

create global temporary table t ( docid number, version number )
on commit delete rows;

а затем, перед выполнением запроса, наполнять временную таблицу данными (используя, по возможности, обработку массивов и обязательно, - ОБЯЗАТЕЛЬНО - связываемые переменные). Затем выполнить следующий простой запрос:

select * 
  from document 
 where (documentid,versionnumber) in (select docid,version from t );

Если не хотите использовать временную таблицу, я бы все равно использовал конструкцию IN, но делал бы это примерно так:

ops$tkyte@ORA8I.WORLD> create or replace type myScalarType as object
  2  ( docid number, version number )
  3  /

Type created.

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> create or replace type myTableType
  2  as table of myScalarType
  3  /

Type created.

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> create or replace
  2  function in_list( p_string in varchar2 )
  3  return myTableType
  4  as
  5      l_string        long default p_string || '|';
  6      l_data          myTableType := myTableType();
  7      n                number;
  8      l_piece            varchar2(255);
  9  begin
 10      loop
 11          exit when l_string is null;
 12          n := instr( l_string, '|' );
 13          l_data.extend;
 14          l_piece := substr( l_string, 1, n-1 );
 15          l_string := substr( l_string, n+1 );
 16  
 17          n := instr( l_piece,',');
 18          l_data(l_data.count) :=
 19              myScalarType( substr(l_piece,1,n-1),
 20                            substr(l_piece,n+1) );
 21      end loop;
 22  
 23      return l_data;
 24  end;
 25  /

Function created.

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> drop table document;

Table dropped.

ops$tkyte@ORA8I.WORLD> create table document ( docid number, version number );

Table created.

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> insert into document values ( 1, 1 );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into document values ( 2, 2 );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into document values ( 3, 3 );

1 row created.

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> variable str varchar2(4000);
ops$tkyte@ORA8I.WORLD> exec :str := '1,1|3,3'

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> select *
  2    from document
  3   where (docid,version) in
  4             ( select *
  5                 from TABLE(cast (in_list(:str) as myTableType)
  6                           )
  7             )
  8  /

     DOCID    VERSION
---------- ----------
         1          1
         3          3

ops$tkyte@ORA8I.WORLD> 

Обсуждение

Сравните с точки зрения накладных расходов. Комментарий SK 2 июля 2002 года

Привет, Том!

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

Ответ дяди Тома

Измерьте производительность! Я бы сделал именно так (я бы использовал массив для небольших объемов данных и временную таблицу, если данных побольше).

Оригинал обсуждения этого вопроса можно найти здесь. Некоторые несущественные детали и комментарии читателей не переведены.


В следующем выпуске

Как получить информативное приглашение в командной строке SQL*Plus. Том Кайт о мутирующих таблицах. Следите за новостями на сайте проекта Open Oracle.

С наилучшими пожеланиями,

  В.К.



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное