Subject Re: Query plan insists on NOT USING an index
Author Franz J Fortuny
The solution suggested by Set has been built into the procedure that
was executing the query and things are now OK as far as speed
(instantaneously) is concerned.

The ones that I did try (after other suggestions) that didn't work,
are, for example, this one:

select a.descri,a.idsubarti,
coalesce(ex.existe,0.0),
b.idarea,
coalesce((
select sum(unids) from facrens aa join facturas bb on
bb.idfactura=aa.idfactura
and aa.idsubarti=a.idsubarti and aa.idarea=b.idarea and bb.idfacedo
in (2,12,25)
),0.0)
as reser, a.serial,c.cosba,cast(c.pventa as
numeric(12,2)),cast(c.pventa2 as numeric(12,2)),b.area
from subartis a
join nipres c on c.idarti=a.idarti and c.nipre=a.nipre
left outer join exiareas ex on ex.idsubarti=a.idsubarti
left outer join areas b on b.idarea=ex.idarea
join tor_equiv te on te.idsub2=a.idsubarti and te.idsub1=:ids

Plan:

PLAN JOIN (AA INDEX (RDB$FOREIGN242, RDB$FOREIGN241), BB INDEX
(RDB$PRIMARY119))
PLAN JOIN (AA INDEX (RDB$FOREIGN242, RDB$FOREIGN241), BB INDEX
(RDB$PRIMARY119))
PLAN JOIN (JOIN (JOIN (JOIN (A NATURAL, C INDEX (RDB$PRIMARY131)), EX
INDEX (RDB$FOREIGN229)), B INDEX (RDB$PRIMARY96)), TE INDEX
(UNQ_TOR_EQUIV_1))

(As you can see, IT IS using the proper index for TOR_EQUIV, but not
for A (subartis), WHERE it insists on the "NATURAL").

This one DID WORK:

select a.descri,a.idsubarti,
coalesce(ex.existe,0.0),
b.idarea,
coalesce((
select sum(unids) from facrens aa join facturas bb on
bb.idfactura=aa.idfactura
and aa.idsubarti=a.idsubarti and aa.idarea=b.idarea and bb.idfacedo
in (2,12,25)
),0.0)
as reser, a.serial,c.cosba,cast(c.pventa as
numeric(12,2)),cast(c.pventa2 as numeric(12,2)),b.area
from subartis a
join nipres c on c.idarti=a.idarti and c.nipre=a.nipre
join tor_equiv te on te.idsub2=a.idsubarti and te.idsub1=:ids
left outer join exiareas ex on ex.idsubarti=a.idsubarti
left outer join areas b on b.idarea=ex.idarea

The Plan:

PLAN JOIN (AA INDEX (RDB$FOREIGN242, RDB$FOREIGN241), BB INDEX
(RDB$PRIMARY119))
PLAN JOIN (AA INDEX (RDB$FOREIGN242, RDB$FOREIGN241), BB INDEX
(RDB$PRIMARY119))
PLAN JOIN (JOIN (JOIN (TE INDEX (FK_TOR_EQUIV_1), A INDEX
(RDB$PRIMARY179), C INDEX (RDB$PRIMARY131)), EX INDEX
(RDB$FOREIGN229)), B INDEX (RDB$PRIMARY96))

"A" INDEX (RDB$PRIMARY179) which is the primary KEY of SUBARTIS (A).

And, of course, the one suggested by Set, which is a variation of the
above one.

What I have learned, thanks to all of you people, is that the ORDER OF
THE JOINS does affect the PLAN. If JOIN TOR_EQUIV is before the left
outer joins, then the plan is the fast one. However, if the JOIN is
AFTER the "outer joins", then it takes the slow path.

That is tricky. Due note has been taken of this.

Now, if you are interested in my real problem, it is that all of that
was inside a VIEW:

CREATE VIEW VWSUBEXI(
DESCRI,
ID,
EXISTE,
IDAREA,
RESER,
SERIAL,
COSBA,
PVENTA,
PVENTA2,
AREA)
AS
select a.descri,a.idsubarti,
coalesce(ex.existe,0.0),
b.idarea,
coalesce((
select sum(unids) from facrens aa join facturas bb on
bb.idfactura=aa.idfactura
and aa.idsubarti=a.idsubarti and aa.idarea=b.idarea and bb.idfacedo
in (2,12,25)
),0.0)
as reser, a.serial,c.cosba,cast(c.pventa as
numeric(12,2)),cast(c.pventa2 as numeric(12,2)),b.area
from subartis a
join nipres c on c.idarti=a.idarti and c.nipre=a.nipre
left outer join exiareas ex on ex.idsubarti=a.idsubarti
left outer join areas b on b.idarea=ex.idarea

This view returns the existence in an inventory of an area, deducting
any quantities already in committed orders. This view DOES NOT involve
TOR_EQUIV, because this view does not care about equivalent products.

The procedure using the view DID require to join this view with the
TOR_EQUIV table.

And that is where my problems began.

If I execute:

select id,existe from vwsubexi v
join tor_equiv te on te.idsub2 = v.id and te.idsub1 = :ids

IT TAKES THE LENGTHY path! I suppose that is because the view VWSUBEXI
has two LEFT OUTER JOINS.

Changing the OUTER JOINS to JOINS AFFECTS the speed and causes the
execution to be fast, but it does not bring all the data that is needed...

So, today's lesson, for me, is simply that any JOIN after you have
placed LEFT OUTER JOINS will not use the proper indexes, and if you
need such thing, then you must place the JOIN BEFORE the "left outer"
JOINS.

Thanks for the lesson, group!

I hope other will learn from this.

FJFortuny