powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Проблема с Plan когда во Where есть in(,,,,)
14 сообщений из 14, страница 1 из 1
Проблема с Plan когда во Where есть in(,,,,)
    #32243319
Из-за неэффективности планировщика запросов Interbase (медленнее в 30 раз, чем в явно заданном мною плане для некоторого множества типовых запросов к таблицам бухгалтерии) есть потребность в такой схеме действий:

1. Спросить у Interbase план запроса
2. Поменять его по выявленному нами алгоритму:
а) поменять порядок параметров в директиве join(таблица1(индексы),таблица2(индексы),...)), т.е. установить оптимальный порядок сканирования таблиц
б) убрать использование лишних индексов для одной из таблиц (там по смыслу всегда нужен единственный индекс)
3. Послать в Interbase запрос с явно заданным планом

Но возникает очень серьезная проблема, когда во WHERE для ключевых полей есть ограничение по IN, например, WHERE (Date>'01.01.2003') AND (AccID in (111,222,333)). В этом случае Interbase в плане запроса указывает использовать индекс по AccID несколько раз: PLAN SORT(JOIN(Entry(Entry_Date, Entry_AccID, Entry_AccID, Entry_AccID))). Однако, попытка использовать этот план явно терпит фиаско :((( Interbase выдает сообщение, что индекс Entry_AccID не м.б. использован в этом случае.

Возникает предположение, что индексные поля, ограниченные IN(....) действительно не м.б. использованы в плане. Но это неверно! Указываю явный план SORT(JOIN(Entry(Entry_Date))) и выборка идет медленнее в 2 раза, чем если план не указывать (т.е. используется план по умолчанию, упоминавшийся выше).

ТАКИМ ОБРАЗОМ:
Проблема: для in(,,,) IB показывает план запроса в синтаксисе непригодном для явного использования.
Вопрос: кто подскажет верный синтаксис?
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32243374
Фотография Johnmen
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Давай по-порядку...
Приводи текст запроса, приводи план(ы)
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32243480
Итак, по порядку:

1. Запрос:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select A.DC,Sum(A.Total) as Total,Sum(A.Quantity) as Quantity, A.LA_12100086 as FieldUsersSection0, A.Price as FieldUsersSection1 From EntryCorr_12000101 A
  join EntryCorr_12000101 CC on CC.SeniorID=A.SeniorID and A.ID<>CC.ID
WHERE  (A.ACCSUBJID =  12000101 )
  AND (A.AccID in ( 12600011 , 12600012 , 12600013 , 12600014 , 12600015 , 12600016 , 12600017 , 12600018 , 12600019 , 12100092 , 12600020 , 12600021 , 12600022 , 12600023 , 12600024 , 12600025 , 12600026 , 12600027 , 15000687 , 12100093 , 13213699 ))
  AND (A.EXECTIME>= "01 . 08 . 2002 ") AND (A.EXECTIME<= "31 . 08 . 2002   23 : 59 : 59 ")
  AND ( 44123 =A.STATE) AND (A.STATE <> 60028 )
  AND ( CC.EXECTIME<= "31 . 08 . 2002   23 : 59 : 59 " ) AND (CC.EXECTIME>= "01 . 08 . 2002 ")
  AND A.DC =  1 
  AND CC.LA_64006 =  13442158 
  AND CC.AccId in ( 12600081 , 12100919 , 12100225 , 13334131 , 12100920 , 1023055 , 12100930 )
Group By A.LA_12100086,A.Price,A.DC
  Having A.LA_12100086 is Not Null  AND A.Price is Not Null


2. План, используемый Interbase по информации IB Console
Код: plaintext
1.
2.
3.
SORT (JOIN (
  CC INDEX (ENTRYCORR_12000101EXECTIME, ENTRYCORR_12000101LA_64006, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID)
  , A INDEX (ENTRYCORR_12000101SENIORID, ENTRYCORR_12000101EXECTIME, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID, ENTRYCORR_12000101ACCID)))


3. Статистика:
Execution time 9 s
Prepare Time 0
Starting Memory 17800192
Current Memory 21239808
DeltaMemory 3439616
Number of Buffers 2048
Reads 357
Writes 5

4. Запрос с явным планом, который я указываю:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
select A.DC,Sum(A.Total) as Total,Sum(A.Quantity) as Quantity, A.LA_12100086 as FieldUsersSection0, A.Price as FieldUsersSection1 From EntryCorr_12000101 A
  join EntryCorr_12000101 CC on CC.SeniorID=A.SeniorID and A.ID<>CC.ID
WHERE  (A.ACCSUBJID =  12000101 )
  AND (A.AccID in ( 12600011 , 12600012 , 12600013 , 12600014 , 12600015 , 12600016 , 12600017 , 12600018 , 12600019 , 12100092 , 12600020 , 12600021 , 12600022 , 12600023 , 12600024 , 12600025 , 12600026 , 12600027 , 15000687 , 12100093 , 13213699 ))
  AND (A.EXECTIME>= "01 . 08 . 2002 ") AND (A.EXECTIME<= "31 . 08 . 2002   23 : 59 : 59 ")
  AND ( 44123 =A.STATE) AND (A.STATE <> 60028 )
  AND ( CC.EXECTIME<= "31 . 08 . 2002   23 : 59 : 59 " ) AND (CC.EXECTIME>= "01 . 08 . 2002 ")
  AND A.DC =  1 
  AND CC.LA_64006 =  13442158 
  AND CC.AccId in ( 12600081 , 12100919 , 12100225 , 13334131 , 12100920 , 1023055 , 12100930 )
Group By A.LA_12100086,A.Price,A.DC
  Having A.LA_12100086 is Not Null  AND A.Price is Not Null
Plan SORT (JOIN (A INDEX (ENTRYCORR_12000101EXECTIME)
                ,CC INDEX (ENTRYCORR_12000101SENIORID)
                 )
          )


5. Статистика с моим планом:
Execution time 1.06 s
Prepare Time 0
Starting Memory 17806336
Current Memory 17961984
DeltaMemory 155648
Number of Buffers 2048
Reads 1713
Writes 11

6. Проблема:
Хочу план по алиасу CC таким и оставить:
Код: plaintext
CC INDEX (ENTRYCORR_12000101SENIORID)

т.к. здесь нужен единственный индекс, а вот для алиаса A я хотел бы использовать индекс ENTRYCORR_12000101ACCID по полю ACCID, но Interbase ругается. Более того, если я просту явно укажу первый вариант плана, который сам же Interbase мне и предоставил, то ошибка та же:

Index ENTRYCORR_12000101ACCID cannot be used in the specified plan.
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32243622
Фотография Johnmen
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Странно все это...
Про плановое хозяйство почитай здесь, очень полезно :

...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32243629
Фотография Johnmen
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
http://www.krista.ru/ib/
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32243669
Voha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А запрос ты формируешь динамически на клиенте , я имеюю в виду:

Код: plaintext
1.
2.
  AND (A.AccID in ( 12600011 , 12600012 , 12600013 , 12600014 , 12600015 , 12600016 , 12600017 , 12600018 , 12600019 , 12100092 , 12600020 , 12600021 , 12600022 , 12600023 , 12600024 , 12600025 , 12600026 , 12600027 , 15000687 , 12100093 , 13213699 ))
  
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32243674
Voha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да и еще
http://ibase.ru/devinfo/dontdoit.htm][пункт №15]
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32243733
> VOVA: А запрос ты формируешь динамически на клиенте , я имеюю в виду:

Да, на стороне клиента есть библиотека, которая по некоторому стандартизированному запросу к бухитогам в объектной нотации выдает SQL ваиант на сервер, получает результат и позволяет опять таки в объектной нотации разобрать этот результат.

> VOVA: Да и еще [пункт №15]

Спасибо за совет, подумаем.
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32244023
Alexandr K.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
1. Попробовать перегенерировать селективность индексов (SET STATISTICS)
2. Наверно надо избавиться от HAVING (перенести условия NOT NULL в WHERE)
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32244137
> Voha
Мои глубочайшие извинения за ошибку в указании Вашего имени.

> Alexandr K.
Благодарю за помощь, я так и попробовал, но результат тот же "Index ENTRYCORR_12000101ACCID cannot be used in the specified plan".

После многодневных экспериментов я убедился, что причина единственная - ошибка в Interbase, касающаяся синтаксиса планов, когда есть where...in...
Для обоснования упрощаю исходный запрос до предела (вопросы производительности join уже подняты и обоснованы, теперь сконцентрируемся только на проблемах синтаксиса).

Итак, для запроса:
Код: plaintext
1.
2.
3.
4.
5.
SET STATISTICS INDEX ENTRYCORR_12000101EXECTIME;
SET STATISTICS INDEX ENTRYCORR_12000101AccID;
select ID From EntryCorr_12000101 A
WHERE A.AccID in ( 12600011 , 12600018 )
  AND A.EXECTIME>= "01 . 08 . 2002 " AND A.EXECTIME<= "31 . 08 . 2002   23 : 59 : 59 "


Interbase по данным IB Console использует план:
Код: plaintext
1.
PLAN (A INDEX (ENTRYCORR_12000101EXECTIME,ENTRYCORR_12000101ACCID,ENTRYCORR_12000101ACCID))


Пробую его "тупо" подставить (не забывая о переделке статистики индексов):
Код: plaintext
1.
2.
3.
4.
5.
6.
SET STATISTICS INDEX ENTRYCORR_12000101EXECTIME;
SET STATISTICS INDEX ENTRYCORR_12000101AccID;
select ID From EntryCorr_12000101 A
WHERE A.AccID in ( 12600011 , 12600018 )
  AND A.EXECTIME>= "01 . 08 . 2002 " AND A.EXECTIME<= "31 . 08 . 2002   23 : 59 : 59 "
PLAN (A INDEX (ENTRYCORR_12000101EXECTIME,ENTRYCORR_12000101ACCID,ENTRYCORR_12000101ACCID))


Получаю диалоговое окно с ошибкой:
Код: plaintext
1.
2.
3.
SQL Error
Detail Message:
Index ENTRYCORR_12000101ACCID cannot be used in the specified plan .....


Теперь убираю IN и проверяю бухсчет на равенство:
Код: plaintext
1.
2.
3.
4.
5.
6.
SET STATISTICS INDEX ENTRYCORR_12000101EXECTIME;
SET STATISTICS INDEX ENTRYCORR_12000101AccID;
select ID From EntryCorr_12000101 A
WHERE A.AccID =  12600018 
  AND A.EXECTIME>= "01 . 08 . 2002 " AND A.EXECTIME<= "31 . 08 . 2002   23 : 59 : 59 "
PLAN (A INDEX (ENTRYCORR_12000101EXECTIME,ENTRYCORR_12000101ACCID))


Все прекрасно работает.
Таким образом ясно одно: для IN - Interbase использует индексы, но отображает план для этого случая некорректно, или отображает корректно, но некорректно на него реагирует при явном указании в SELECT. А какой синтаксис корректный - не ясно.

P.S. Если не использовать
Код: plaintext
1.
2.
SET STATISTICS INDEX ENTRYCORR_12000101EXECTIME;
SET STATISTICS INDEX ENTRYCORR_12000101AccID;

то результат тот же.
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32244188
Voha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я может не совсем вдуплил, но может стоит использовать временную таблу и на основе ее производить проверку?
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32244716
> Voha: ... использовать временную таблу ...

Попробовал. И вышло следующее.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
create table sotrudnik (name char( 30 ), otdel  integer);

create index sotrudnik_otdel on sotrudnik (otdel);

insert into sotrudnik (name,otdel) values ('Ivanov', 1 );
insert into sotrudnik (name,otdel) values ('Petrov', 2 );
insert into sotrudnik (name,otdel) values ('Sidorov', 3 );

select * from sotrudnik where otdel in ( 1 , 2 )
plan (sotrudnik index (sotrudnik_otdel))


Сработало! Хотя Interbase и показал для данного указанного плана его фактический план:
Код: plaintext
1.
plan (sotrudnik index (sotrudnik_name,sotrudnik_otdel,sotrudnik_otdel))


Опаньки!!! Нашел причину. Причина должны была быть в отличии а отличие в том, что я "пожадничал" и не создал поле ID оно же Primary Key. Итак, удаляю таблицу и ключ и делаю все заново, но с ID.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
create table sotrudnik
(
 id      integer not null,
 name char( 30 ),
 otdel  integer,
 primary key (id)
);

create index sotrudnik_otdel on sotrudnik (otdel);

insert into sotrudnik (id,name,otdel) values ( 1 ,'Ivanov', 1 );
insert into sotrudnik (id,name,otdel) values ( 2 ,'Petrov', 2 );
insert into sotrudnik (id,name,otdel) values ( 3 ,'Sidorov', 3 );

select * from sotrudnik where otdel in ( 1 , 2 )
plan (sotrudnik index (sotrudnik_otdel))

Не работает!
Вылетает старая добрая ошибка, что sotrudnik_otdel использовать в плане нельзя. Тогда пробую ради прикола применить это ограничение к полю с первичным ключом:
Код: plaintext
1.
2.
select * from sotrudnik where id in ( 1 , 2 )
plan (sotrudnik index (RDB$PRIMARY533))

Работает! Можете проверить.

Вывод:
Interbase использует индекс, но не дает явно указывать его в плане запроса, если этот индекс не Primary Key или если по другому полю есть Primary Key. Железная логика у интербейза .

Еще один повод задуматься о всеобщем детерминизме и фатализме :).

Что же делать?....
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32244769
Maks_f
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Попробуй FIB там много вещей исправлено, которые в интербасе работали некорректно.
...
Рейтинг: 0 / 0
Проблема с Plan когда во Where есть in(,,,,)
    #32252326
>Maks_f
Точно! В FIB работает. Странно, почему Borland не исправил такой явный баг в IB 7.0?

Кто-нибудь знает, как до них достучаться (если не являешься официальным юзером)?
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Проблема с Plan когда во Where есть in(,,,,)
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]