Subject | Query otimization - Why this plan ? |
---|---|
Author | Alexandre Benson Smith |
Post date | 2005-03-15T01:59:19Z |
Hi Guys,
Using FB 1.5.1 SS on Windows XP
I have a query (the * was in the query just to make it short I have a
column list there) and was intrigued by the choosen plan:
select
*
from
Empresa e join
Cliente c on (e.EmpresaId =
c.EmpresaId) join
SegmentoMercado s on (s.SegmentoMercadoId =
c.SegmentoMercadoId) join
Vendedor v on (v.VendedorId =
c.VendedorId) join
Empresa et on (et.EmpresaId =
c.TransportadoraId) join
Empresa ed on (ed.EmpresaId =
c.DistribuidorId) join
ListaPreco lp on (lp.ListaPrecoId =
c.ListaPrecoId) left join
Endereco en on ((en.EmpresaID = c.EmpresaID)
and (en.Tipo = 1)) left join
Estado es on (es.EstadoID = en.EstadoID)
where
e.Nome = 'Alexandre Benson Smith'
I get this plan:
PLAN JOIN (JOIN (JOIN (LP NATURAL,C INDEX (FK_CLIENTE_LISTAPRECO),ED
INDEX (PK_EMPRESA),E INDEX (AK_EMPRESA_NOME),S INDEX
(PK_SEGMENTOMERCADO),V INDEX (PK_VENDEDOR),ET INDEX (PK_EMPRESA)),EN
INDEX (FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
C.ListaPrecoID will be a very poor index, so I tried to avoid his use
with this query (using +0):
select
*
from
Empresa e join
Cliente c on (e.EmpresaId =
c.EmpresaId) join
SegmentoMercado s on (s.SegmentoMercadoId =
c.SegmentoMercadoId) join
Vendedor v on (v.VendedorId =
c.VendedorId) join
Empresa et on (et.EmpresaId =
c.TransportadoraId) join
Empresa ed on (ed.EmpresaId =
c.DistribuidorId) join
ListaPreco lp on (lp.ListaPrecoId =
c.ListaPrecoId + 0) left join
Endereco en on ((en.EmpresaID = c.EmpresaID)
and (en.Tipo = 1)) left join
Estado es on (es.EstadoID = en.EstadoID)
where
e.Nome = 'Alexandre Benson Smith'
the plan is:
PLAN JOIN (JOIN (JOIN (C NATURAL,LP INDEX (PK_LISTAPRECO),E INDEX
(AK_EMPRESA_NOME),S INDEX (PK_SEGMENTOMERCADO),V INDEX (PK_VENDEDOR),ET
INDEX (PK_EMPRESA),ED INDEX (PK_EMPRESA)),EN INDEX
(FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
I have expected the following plan:
PLAN JOIN (JOIN (JOIN (E INDEX (AK_EMPRESA_NOME), C INDEX(PK_CLIENTE),LP
INDEX (PK_LISTAPRECO),S INDEX (PK_SEGMENTOMERCADO),V INDEX
(PK_VENDEDOR),ET INDEX (PK_EMPRESA),ED INDEX (PK_EMPRESA)),EN INDEX
(FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
If I force this plan I get far better result and of course just one read
on the majority of the tables and 3 reads on table Empresa (that is used
3 times in this query)
This query returns just one record, and I have a unique index on E.Nome
that is a varchar(40)
the rdb$statistics for that index is 9,64041246334091E-5
if I force a "fake left join" (to force table Empresa to be the first
scanned table) I get a plan similar to what I expected:
select
*
from
Empresa e left join
Cliente c on (e.EmpresaId =
c.EmpresaId) join
SegmentoMercado s on (s.SegmentoMercadoId =
c.SegmentoMercadoId) join
Vendedor v on (v.VendedorId =
c.VendedorId) join
Empresa et on (et.EmpresaId =
c.TransportadoraId) join
Empresa ed on (ed.EmpresaId =
c.DistribuidorId) join
ListaPreco lp on (lp.ListaPrecoId =
c.ListaPrecoId + 0) left join
Endereco en on ((en.EmpresaID = c.EmpresaID)
and (en.Tipo = 1)) left join
Estado es on (es.EstadoID = en.EstadoID)
where
e.Nome = 'Alexandre Benson Smith'
PLAN JOIN (JOIN (JOIN (JOIN (E INDEX (AK_EMPRESA_NOME),C INDEX
(PK_CLIENTE)),JOIN (S INDEX (PK_SEGMENTOMERCADO),LP INDEX
(PK_LISTAPRECO),ED INDEX (PK_EMPRESA),ET INDEX (PK_EMPRESA),V INDEX
(PK_VENDEDOR))),EN INDEX (FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
Even if I just change the first 2 table order I get a bad plan again
select
*
from
Cliente c join
Empresa e on (e.EmpresaId =
c.EmpresaId) left join
SegmentoMercado s on (s.SegmentoMercadoId =
c.SegmentoMercadoId) join
Vendedor v on (v.VendedorId =
c.VendedorId) join
Empresa et on (et.EmpresaId =
c.TransportadoraId) join
Empresa ed on (ed.EmpresaId =
c.DistribuidorId) join
ListaPreco lp on (lp.ListaPrecoId =
c.ListaPrecoId + 0) left join
Endereco en on ((en.EmpresaID = c.EmpresaID)
and (en.Tipo = 1)) left join
Estado es on (es.EstadoID = en.EstadoID)
where
e.Nome = 'Alexandre Benson Smith'
PLAN JOIN (JOIN (JOIN (JOIN (JOIN (C NATURAL,E INDEX
(AK_EMPRESA_NOME)),S INDEX (PK_SEGMENTOMERCADO)),JOIN (V INDEX
(PK_VENDEDOR),LP INDEX (PK_LISTAPRECO),ED INDEX (PK_EMPRESA),ET INDEX
(PK_EMPRESA))),EN INDEX (FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
The statistics are updated, I have dropped and recreated the index, have
backup/restore the db, but nothing changes the plan.
the above query is a view, I cant force the fake plan, because I could
search on other fields too (V.Nome, S.Descricao, ES.Sigla, etc.)
Why the optimizer don't priorize the unique index if I am searching for
a specific value on that column ???
:-/
Any Ideas ?
Any more info I could supply to help you understand what's happenning ?
Thank you !
--
Alexandre Benson Smith
Development
THOR Software e Comercial Ltda.
Santo Andre - Sao Paulo - Brazil
www.thorsoftware.com.br
--
No virus found in this outgoing message.
Checked by AVG Anti-Virus.
Version: 7.0.308 / Virus Database: 266.7.2 - Release Date: 11/03/2005
Using FB 1.5.1 SS on Windows XP
I have a query (the * was in the query just to make it short I have a
column list there) and was intrigued by the choosen plan:
select
*
from
Empresa e join
Cliente c on (e.EmpresaId =
c.EmpresaId) join
SegmentoMercado s on (s.SegmentoMercadoId =
c.SegmentoMercadoId) join
Vendedor v on (v.VendedorId =
c.VendedorId) join
Empresa et on (et.EmpresaId =
c.TransportadoraId) join
Empresa ed on (ed.EmpresaId =
c.DistribuidorId) join
ListaPreco lp on (lp.ListaPrecoId =
c.ListaPrecoId) left join
Endereco en on ((en.EmpresaID = c.EmpresaID)
and (en.Tipo = 1)) left join
Estado es on (es.EstadoID = en.EstadoID)
where
e.Nome = 'Alexandre Benson Smith'
I get this plan:
PLAN JOIN (JOIN (JOIN (LP NATURAL,C INDEX (FK_CLIENTE_LISTAPRECO),ED
INDEX (PK_EMPRESA),E INDEX (AK_EMPRESA_NOME),S INDEX
(PK_SEGMENTOMERCADO),V INDEX (PK_VENDEDOR),ET INDEX (PK_EMPRESA)),EN
INDEX (FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
C.ListaPrecoID will be a very poor index, so I tried to avoid his use
with this query (using +0):
select
*
from
Empresa e join
Cliente c on (e.EmpresaId =
c.EmpresaId) join
SegmentoMercado s on (s.SegmentoMercadoId =
c.SegmentoMercadoId) join
Vendedor v on (v.VendedorId =
c.VendedorId) join
Empresa et on (et.EmpresaId =
c.TransportadoraId) join
Empresa ed on (ed.EmpresaId =
c.DistribuidorId) join
ListaPreco lp on (lp.ListaPrecoId =
c.ListaPrecoId + 0) left join
Endereco en on ((en.EmpresaID = c.EmpresaID)
and (en.Tipo = 1)) left join
Estado es on (es.EstadoID = en.EstadoID)
where
e.Nome = 'Alexandre Benson Smith'
the plan is:
PLAN JOIN (JOIN (JOIN (C NATURAL,LP INDEX (PK_LISTAPRECO),E INDEX
(AK_EMPRESA_NOME),S INDEX (PK_SEGMENTOMERCADO),V INDEX (PK_VENDEDOR),ET
INDEX (PK_EMPRESA),ED INDEX (PK_EMPRESA)),EN INDEX
(FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
I have expected the following plan:
PLAN JOIN (JOIN (JOIN (E INDEX (AK_EMPRESA_NOME), C INDEX(PK_CLIENTE),LP
INDEX (PK_LISTAPRECO),S INDEX (PK_SEGMENTOMERCADO),V INDEX
(PK_VENDEDOR),ET INDEX (PK_EMPRESA),ED INDEX (PK_EMPRESA)),EN INDEX
(FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
If I force this plan I get far better result and of course just one read
on the majority of the tables and 3 reads on table Empresa (that is used
3 times in this query)
This query returns just one record, and I have a unique index on E.Nome
that is a varchar(40)
the rdb$statistics for that index is 9,64041246334091E-5
if I force a "fake left join" (to force table Empresa to be the first
scanned table) I get a plan similar to what I expected:
select
*
from
Empresa e left join
Cliente c on (e.EmpresaId =
c.EmpresaId) join
SegmentoMercado s on (s.SegmentoMercadoId =
c.SegmentoMercadoId) join
Vendedor v on (v.VendedorId =
c.VendedorId) join
Empresa et on (et.EmpresaId =
c.TransportadoraId) join
Empresa ed on (ed.EmpresaId =
c.DistribuidorId) join
ListaPreco lp on (lp.ListaPrecoId =
c.ListaPrecoId + 0) left join
Endereco en on ((en.EmpresaID = c.EmpresaID)
and (en.Tipo = 1)) left join
Estado es on (es.EstadoID = en.EstadoID)
where
e.Nome = 'Alexandre Benson Smith'
PLAN JOIN (JOIN (JOIN (JOIN (E INDEX (AK_EMPRESA_NOME),C INDEX
(PK_CLIENTE)),JOIN (S INDEX (PK_SEGMENTOMERCADO),LP INDEX
(PK_LISTAPRECO),ED INDEX (PK_EMPRESA),ET INDEX (PK_EMPRESA),V INDEX
(PK_VENDEDOR))),EN INDEX (FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
Even if I just change the first 2 table order I get a bad plan again
select
*
from
Cliente c join
Empresa e on (e.EmpresaId =
c.EmpresaId) left join
SegmentoMercado s on (s.SegmentoMercadoId =
c.SegmentoMercadoId) join
Vendedor v on (v.VendedorId =
c.VendedorId) join
Empresa et on (et.EmpresaId =
c.TransportadoraId) join
Empresa ed on (ed.EmpresaId =
c.DistribuidorId) join
ListaPreco lp on (lp.ListaPrecoId =
c.ListaPrecoId + 0) left join
Endereco en on ((en.EmpresaID = c.EmpresaID)
and (en.Tipo = 1)) left join
Estado es on (es.EstadoID = en.EstadoID)
where
e.Nome = 'Alexandre Benson Smith'
PLAN JOIN (JOIN (JOIN (JOIN (JOIN (C NATURAL,E INDEX
(AK_EMPRESA_NOME)),S INDEX (PK_SEGMENTOMERCADO)),JOIN (V INDEX
(PK_VENDEDOR),LP INDEX (PK_LISTAPRECO),ED INDEX (PK_EMPRESA),ET INDEX
(PK_EMPRESA))),EN INDEX (FK_EMPRESA_ENDERECO)),ES INDEX (PK_ESTADO))
The statistics are updated, I have dropped and recreated the index, have
backup/restore the db, but nothing changes the plan.
the above query is a view, I cant force the fake plan, because I could
search on other fields too (V.Nome, S.Descricao, ES.Sigla, etc.)
Why the optimizer don't priorize the unique index if I am searching for
a specific value on that column ???
:-/
Any Ideas ?
Any more info I could supply to help you understand what's happenning ?
Thank you !
--
Alexandre Benson Smith
Development
THOR Software e Comercial Ltda.
Santo Andre - Sao Paulo - Brazil
www.thorsoftware.com.br
--
No virus found in this outgoing message.
Checked by AVG Anti-Virus.
Version: 7.0.308 / Virus Database: 266.7.2 - Release Date: 11/03/2005