Явный и неявный JOIN

Модераторы: kdv, CyberMax

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 02 окт 2006, 18:53

Чёрт, совсем нет времени сочинить прозрачный пример :( Кидаю живой запрос, может всё-таки получится понять:

Код: Выделить всё

     Select Coalesce(Sum(CL.WKolInt/N.TonIntrn*1e-06),0.000), Count( *)
      From MP_MGSost MGS
        Join UAG_Members UAM
         On UAM.Gruppa=MGS.CodeUAG And UAM.TipZap=1
        /*Left*/ Join Claims CL
         On CL.KodTov=UAM.KodTov And CL.PStatus=1
        Join ClaimPrZak CPZ
         On CPZ.Filial=CL.Filial And CPZ.Claim=CL.Code And CPZ.Priznak='Д'
        Join Nomenkl N
         On N.Code=CL.KodTov
        Join Sellers_Marks SM
         On SM.Mark=N.Mark And SM.Seller=:Seller
        Left Join X_LMGS_CL XCL
         On XCL.Filial=CPZ.Filial And XCL.CodeCL=CPZ.Claim
       Where MGS.CodeMG=:CodeMG And XCL.Letter Is Null
       Plan JOIN (MGS INDEX (MP_MGSOST_MG),
           UAM INDEX (UAM_FKGR),
           CL INDEX (CL_KTSTFL),
           CPZ INDEX (CLAIMPRZAK_PFC),
           N INDEX (Nmnkl_Co),
           SM INDEX (SM_SELMARK),
           XCL INDEX (XLMGSCL_FKC))
Здесь основное усечение выборки даёт CL.PStatus=1, которое участвует в композитном индексе CL_KTSTFL - KodTov, PStatus, Code. Что и зафиксировано в секции Plan, которая должна бы управлять не только индексами, но порядком объединений. И в случае когда все джойны inner, так оно и происходит. Однако, как только оптимайзер увидит Left, он молча забивает на секцию Plan и делает всё по-своему, хотя порядок объединений ДО этого Left его вообще-то не касается. В данном случае получается

Код: Выделить всё

PLAN JOIN (JOIN (MGS INDEX (MP_MGSOST_MG),
                          SM INDEX (SM_SELMARK),
                          CPZ INDEX (CLAIMPRZAK_PFC),
                          UAM INDEX (UAM_FKGR),
                          CL INDEX (CL_KTSTFL),
                          N INDEX (NMNKL_CO)),
                          XCL INDEX (XLMGSCL_FKC))
то есть таблица CL задвинута именно в эту круглую-белую с третьего места. И хинтами не подрулить - индексы-то использует все те же, но не в том порядке. В итоге время выполнения увеличивается на пару порядков. Опять же в данном конкретном случае характер данных позволяет малость улучшить ситуацию заменой присоединения этой таблицы на Left (закомментаренный в запросе выше), но в общем случае это будет совсем другой по смыслу запрос :( И он всё равно проигрывает чистому inner, который тут не катит, поскольку ищутся именно не существующие в последней таблице записи. Not Exists на этих данных тоже сильно проигрывает.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 03 окт 2006, 12:21

Спасибо, пример понятен.
Хотя конечно соблазн самому "покрутить" запрос руками велик :oops: С трудом, но заставляю себя верить, что действительно ничего нельзя сделать.

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 03 окт 2006, 17:07

Если это баг, то пусть разработчики правят его :).

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 03 окт 2006, 18:06

В двойке по идее должен быть уже исправлен.

Ответить