Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Informix Новый топик    Ответить
 Производительность запросов с Set  [new]
falcon111
Member

Откуда:
Сообщений: 117
Делаю вычисления с пересечением множеств.
Проходят вычисления по таблице, обновляются-добавляются-удаляются записи, в конце по этой же таблице надо смотреть какие записи не попали в обработку, и выдать по ним упоминания в лог ошибок.

Делалось так: Идет обработка таблицы, ид обработанных записей заносятся в set (integer not null), под конец делается
select id from maintable where id not in table(setvariable) - это выдает ид подвисших записей.
Все бы хорошо, но выполнение конкретно этого запроса занимало десятки секунд. как я там ни изгалялся - ничего не помогало.

Переделал на создание временной таблицы с одним полем с ид
При обработке основной таблицы вместо сета идшники заносятся в эту таблицу,
Для вычисления пересечения создаю вторую временную таблицу, в нее insert всех ид из основной таблицы, затем delete из нее where id in (select id from temptable1)
Это - отрабатывает за доли секунды, хотя на первый взгляд работы серверу больше - во первых копируются ВСЕ ид основной таблицы, потом из нее удаляются ид обработанных записей... А работает быстро.

Объясните почему такая хрень?

Сервер 12.10fc6
Спасибо.
23 сен 16, 14:57    [19700922]     Ответить | Цитировать Сообщить модератору
 Re: Производительность запросов с Set  [new]
АнатоЛой
Member

Откуда: Киев, Украина
Сообщений: 2896
Блог
falcon111, как насчёт мысли, что всё дело в индекса и оптимизаторе? В каком случае есть индексы и какие? Какие планы делает оптимизатор в обоих случаях?
25 сен 16, 11:29    [19705511]     Ответить | Цитировать Сообщить модератору
 Re: Производительность запросов с Set  [new]
falcon111
Member

Откуда:
Сообщений: 117
АнатоЛой,

Доступа к файловой системе сервера в данный момент у меня нет, эксплейн не посмотрю.

Вот код:
drop procedure if exists test_performance_issues;
create procedure test_performance_issues(Method integer) returning varchar(32) as ExecTime;
  define b      bigint;
  define d      double precision;
  define x,v    integer;
  define rc     varchar(32);
  define s      set (integer not null);

  begin
    on exception in (-206)
      create temp table tmp_test_main_data (
        RecId integer primary key
      ) with no log;
      update statistics low for table tmp_test_main_data;
    end exception with resume;
    delete from tmp_test_main_data;
  end;

  for x=1 to 5000
    insert into tmp_test_main_data(RecId) values(x);
  end for;

  if Method==1 then
    let x=1;
    foreach select m.RecId
            into   v
            from tmp_test_main_data m
      insert into table(s) values(v);
      if x==4000 then exit foreach; end if;
      let x=x+1;
    end foreach;
    let b=GetHiResTimer_Start();
    select count(*) into v from tmp_test_main_data m where m.RecId NOT in s;
    let d=GetHiResTimer_Finish(b);
  else
    begin 
    on exception in (-206)
      create temp table tmp_test_intersection (
        RecId integer
      ) with no log;
      update statistics low for table tmp_test_intersection;
      end exception with resume;
      delete from tmp_test_intersection;
    end;
    let x=1;
    foreach select m.RecId
            into   v
            from tmp_test_main_data m
      insert into tmp_test_intersection(RecId) values(v);
      if x==4000 then exit foreach; end if;
      let x=x+1;
    end foreach;
    let b=GetHiResTimer_Start();
    select count(*) into v from tmp_test_Main_Data m where m.RecId NOT in (select i.RecId from tmp_test_intersection i);
    let d=GetHiResTimer_Finish(b);
  end if;
  let d=GetHiResTimer_Finish(b);
  let rc=(d/1000)::numeric(6,3)||'s, '||v||' recs';

  return rc;
end procedure;

update statistics for procedure test_performance_issues;

execute procedure test_performance_issues(1);
execute procedure test_performance_issues(2);

drop procedure test_performance_issues;


Вот результат:
Successfully connected to tb as user informix.
Procedure successfully dropped.
Procedure successfully created.
Statistics successfully updated.
exectime
--------------------------------
1.575s, 1000 recs
1 rows selected.
exectime
--------------------------------
0.031s, 1000 recs
1 rows selected.
Procedure successfully dropped.


Откуда такая разница?
26 сен 16, 20:22    [19710898]     Ответить | Цитировать Сообщить модератору
 Re: Производительность запросов с Set  [new]
АнатоЛой
Member

Откуда: Киев, Украина
Сообщений: 2896
Блог
falcon111, зуб даю, оптимизатор выдал разные планы запросов. В случае с временной таблицей вряд ли он делает 4000 поисков по ключу, но вот пересечение с индексом первичного ключа - запросто. А в случае с множеством - банальных 5000 переборов. Это и по времени видно...
27 сен 16, 00:27    [19711434]     Ответить | Цитировать Сообщить модератору
 Re: Производительность запросов с Set  [new]
falcon111
Member

Откуда:
Сообщений: 117
АнатоЛой,

То, что план разный строит, это очевидно, потом как смогу гляну план выполнения, я просто думал, может есть какие-то тонкости/рекомендации с использованием СЕТов...

Апофеоз.
В моем примере:
select count(*) into v from tmp_test_main_data m where m.RecId NOT in s;
Это ^ выполняется полторы секунды.

select count(*) into v from tmp_test_main_data m where m.RecId NOT in (select * from table(s));
А вот это ^ три сотых секунды.

Если я не прав - объясните в чем, мне пока мыслится это косяком сервера.
Радует только что причину непонятных тупняков я нашел.
27 сен 16, 01:40    [19711525]     Ответить | Цитировать Сообщить модератору
 Re: Производительность запросов с Set  [new]
Daugava
Member

Откуда: Riga-Kiev-Gurzuf
Сообщений: 715
Рекомендация одна - стараться не использовать переменньіх для запросов в процедурах.
27 сен 16, 15:26    [19714004]     Ответить | Цитировать Сообщить модератору
 Re: Производительность запросов с Set  [new]
falcon111
Member

Откуда:
Сообщений: 117
Daugava,

Надежда что в FC7 станет лучше не оправдалась. Все осталось как же, как было.
Исключение только в том что все-таки результат с сетом стал оптимальным.

select count(*) into v from tmp_test_main_data m where m.RecId NOT in (select * from table(s));
дает теперь 0.019s, 1000 recs

select count(*) into v from tmp_test_Main_Data m where m.RecId NOT in (select i.RecId from tmp_test_intersection i);
а это на треть медленнее: 0.030s, 1000 recs

Для себя вопрос считаю исчерпанным.
27 сен 16, 18:57    [19715197]     Ответить | Цитировать Сообщить модератору
Все форумы / Informix Ответить