Subject | Strangely Faster |
---|---|
Author | Antonio Carlos Ribeiro |
Post date | 2009-04-13T14:39:46Z |
Hi!
I would like to understand why "Query A" is 4.57 times faster than "Query B". Here are the timings to get a cursor for both:
Query A
11:13 - Time to process: 00:00:00:719
11:18 - Time to process: 00:00:00:140
Query B
11:13 - Time to process: 00:00:00:157
11:18 - Time to process: 00:00:00:719
The difference between those 2 queries is basically reading fields indirectly with selects in the faster one, like this:
// ----------------------------------------
// extract from Query A
// ----------------------------------------
select
a.codigo_posto
from
L_AGENDA a
where a.CODIGO_POSTO = '01'
and a.DATA >= '04/14/2009 00:00:00'
and a.DATA <= '04/14/2009 23:59:59'
and a.codigo_sala = '01'
order by a.codigo_posto,a.codigo_sala,a.data,a.de,a.ate,a.sequencial_sala,a.encaixe
// ----------------------------------------
// extract from Query B
// ----------------------------------------
select
(select ax.codigo_posto from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_posto
from
L_AGENDA a
where a.CODIGO_POSTO = '01'
and a.DATA >= '04/14/2009 00:00:00'
and a.DATA <= '04/14/2009 23:59:59'
and a.codigo_sala = '01'
order by a.codigo_posto,a.codigo_sala,a.data,a.de,a.ate,a.sequencial_sala,a.encaixe
But it doesn't make any sense to me, because in the slower one Firebird is reading the table once for *each record* and in the faster it is reading one time for *each column*, that makes it search and read *several times the same record*.
Look at the full queries:
/// -------> Query A
select
(select SubStr(StrRepeat('0',4-StrLen(Trim(cast(ax.de as char(4)))))||Trim(cast(ax.de as char(4))),1,2) || ':' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ax.de as char(4)))))||Trim(cast(ax.de as char(4))),3,2) || '-' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ax.ate as char(4)))))||Trim(cast(ax.ate as char(4))),1,2) || ':' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ax.ate as char(4)))))||Trim(cast(ax.ate as char(4))),3,2)
from L_AGENDA ax
where ax.codigo_agendamento = a.codigo_agendamento
and ax.encaixe = a.encaixe) HORA,
(select
StrRepeat('0',2-StrLen(Trim( cast(extractday(ax.data) as char(10)) )))||Trim( cast(extractday(ax.data) as char(10)) ) || ' ' ||
SubStr ( ( case ExtractMonth(ax.data)
when 1 then 'Janeiro'
when 2 then 'Fevereiro'
when 3 then 'Março'
when 4 then 'Abril'
when 5 then 'Maio'
when 6 then 'Junho'
when 7 then 'Julho'
when 8 then 'Agosto'
when 9 then 'Setembro'
when 10 then 'Outubro'
when 11 then 'Novembro'
when 12 then 'Dezembro'
end ), 1, 3 ) || ' ' ||
'(' || SubStr ( ( case ExtractWeekDay(ax.data)
when 0 then 'Domingo'
when 1 then 'Segunda'
when 2 then 'Terça'
when 3 then 'Quarta'
when 4 then 'Quinta'
when 5 then 'Sexta'
when 6 then 'Sábado'
end ), 1, 3 ) || ')'
from L_AGENDA ax
where ax.codigo_agendamento = a.codigo_agendamento
and ax.encaixe = a.encaixe) data_view,
(select ax.data from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) data,
(select ax.codigo_posto from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_posto,
(select ax.codigo_sala from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_sala,
(select ax.de from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) de,
(select ax.ate from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) ate,
(select ax.flag_status from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) flag_status,
(select ax.codigo_funcionario from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_funcionario,
(select ax.codigo_exame from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_exame,
(select ax.codigo_convenio from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_convenio,
(select ax.nome from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) nome,
(select ax.sequencial_sala from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) sequencial_sala,
(select ax.encaixe from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) encaixe,
(select ax.observacao from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) observacao,
(select ax.telefone from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) telefone,
(select ax.codigo_agendamento from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_agendamento,
(select ax.matricula from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) matricula,
(select fs.descricao from L_I_FLAG_STATUS fs where fs.codigo = a.flag_status ) status,
(select s.descricao from L_SALA s where s.codigo_sala = a.codigo_sala) nome_sala,
(select u.nome from B_USUARIO u where u.codigo_usuario = a.codigo_funcionario) nome_funcionario,
(select au.codigo_usuario from L_AGENDA_USO au where au.codigo_agendamento = a.codigo_agendamento and au.encaixe = a.encaixe) em_uso,
(select ax.RESPOSTA_ESPECIAL from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) RESPOSTA_ESPECIAL
from L_AGENDA a
where a.CODIGO_POSTO = '01'
and a.DATA >= '04/14/2009 00:00:00'
and a.DATA <= '04/14/2009 23:59:59'
and a.codigo_sala = '01'
order by a.codigo_posto,a.codigo_sala,a.data,a.de,a.ate,a.sequencial_sala,a.encaixe
/// -------> Query B
select
SubStr(StrRepeat('0',4-StrLen(Trim(cast(de as char(4)))))||Trim(cast(de as char(4))),1,2) || ':' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(de as char(4)))))||Trim(cast(de as char(4))),3,2) || '-' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ate as char(4)))))||Trim(cast(ate as char(4))),1,2) || ':' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ate as char(4)))))||Trim(cast(ate as char(4))),3,2)
hora,
StrRepeat('0',2-StrLen(Trim( cast(extractday(data) as char(10)) )))||Trim( cast(extractday(data) as char(10)) ) || ' ' ||
SubStr ( ( case ExtractMonth(data)
when 1 then 'Janeiro'
when 2 then 'Fevereiro'
when 3 then 'Março'
when 4 then 'Abril'
when 5 then 'Maio'
when 6 then 'Junho'
when 7 then 'Julho'
when 8 then 'Agosto'
when 9 then 'Setembro'
when 10 then 'Outubro'
when 11 then 'Novembro'
when 12 then 'Dezembro'
end ), 1, 3 ) || ' ' ||
-- StrRepeat('0',4-StrLen(Trim( cast(extractyear(data) as char(10)) )))||Trim( cast(extractyear(data) as char(10)) ) || ' ' ||
'(' || SubStr ( ( case ExtractWeekDay(data)
when 0 then 'Domingo'
when 1 then 'Segunda'
when 2 then 'Terça'
when 3 then 'Quarta'
when 4 then 'Quinta'
when 5 then 'Sexta'
when 6 then 'Sábado'
end ), 1, 3 ) || ')' data_view ,
a.data ,
a.codigo_posto ,
a.codigo_sala ,
a.data ,
a.de ,
a.ate ,
a.flag_status ,
a.codigo_funcionario ,
a.codigo_exame ,
a.codigo_convenio ,
a.nome ,
a.sequencial_sala ,
a.encaixe ,
a.observacao ,
a.telefone ,
a.codigo_agendamento ,
a.matricula ,
(select fs.descricao from L_I_FLAG_STATUS fs where fs.codigo = a.flag_status ) status,
(select s.descricao from L_SALA s where s.codigo_sala = a.codigo_sala) nome_sala,
(select u.nome from B_USUARIO u where u.codigo_usuario = a.codigo_funcionario) nome_funcionario,
(select au.codigo_usuario from L_AGENDA_USO au where au.codigo_agendamento = a.codigo_agendamento and au.encaixe = a.encaixe) em_uso,
a.RESPOSTA_ESPECIAL
from L_AGENDA a
where a.CODIGO_POSTO = '01'
and a.DATA >= '04/14/2009 00:00:00'
and a.DATA <= '04/14/2009 23:59:59'
and a.codigo_sala = '01'
order by a.codigo_posto,a.codigo_sala,a.data,a.de,a.ate,a.sequencial_sala,a.encaixe
I would like to understand why "Query A" is 4.57 times faster than "Query B". Here are the timings to get a cursor for both:
Query A
11:13 - Time to process: 00:00:00:719
11:18 - Time to process: 00:00:00:140
Query B
11:13 - Time to process: 00:00:00:157
11:18 - Time to process: 00:00:00:719
The difference between those 2 queries is basically reading fields indirectly with selects in the faster one, like this:
// ----------------------------------------
// extract from Query A
// ----------------------------------------
select
a.codigo_posto
from
L_AGENDA a
where a.CODIGO_POSTO = '01'
and a.DATA >= '04/14/2009 00:00:00'
and a.DATA <= '04/14/2009 23:59:59'
and a.codigo_sala = '01'
order by a.codigo_posto,a.codigo_sala,a.data,a.de,a.ate,a.sequencial_sala,a.encaixe
// ----------------------------------------
// extract from Query B
// ----------------------------------------
select
(select ax.codigo_posto from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_posto
from
L_AGENDA a
where a.CODIGO_POSTO = '01'
and a.DATA >= '04/14/2009 00:00:00'
and a.DATA <= '04/14/2009 23:59:59'
and a.codigo_sala = '01'
order by a.codigo_posto,a.codigo_sala,a.data,a.de,a.ate,a.sequencial_sala,a.encaixe
But it doesn't make any sense to me, because in the slower one Firebird is reading the table once for *each record* and in the faster it is reading one time for *each column*, that makes it search and read *several times the same record*.
Look at the full queries:
/// -------> Query A
select
(select SubStr(StrRepeat('0',4-StrLen(Trim(cast(ax.de as char(4)))))||Trim(cast(ax.de as char(4))),1,2) || ':' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ax.de as char(4)))))||Trim(cast(ax.de as char(4))),3,2) || '-' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ax.ate as char(4)))))||Trim(cast(ax.ate as char(4))),1,2) || ':' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ax.ate as char(4)))))||Trim(cast(ax.ate as char(4))),3,2)
from L_AGENDA ax
where ax.codigo_agendamento = a.codigo_agendamento
and ax.encaixe = a.encaixe) HORA,
(select
StrRepeat('0',2-StrLen(Trim( cast(extractday(ax.data) as char(10)) )))||Trim( cast(extractday(ax.data) as char(10)) ) || ' ' ||
SubStr ( ( case ExtractMonth(ax.data)
when 1 then 'Janeiro'
when 2 then 'Fevereiro'
when 3 then 'Março'
when 4 then 'Abril'
when 5 then 'Maio'
when 6 then 'Junho'
when 7 then 'Julho'
when 8 then 'Agosto'
when 9 then 'Setembro'
when 10 then 'Outubro'
when 11 then 'Novembro'
when 12 then 'Dezembro'
end ), 1, 3 ) || ' ' ||
'(' || SubStr ( ( case ExtractWeekDay(ax.data)
when 0 then 'Domingo'
when 1 then 'Segunda'
when 2 then 'Terça'
when 3 then 'Quarta'
when 4 then 'Quinta'
when 5 then 'Sexta'
when 6 then 'Sábado'
end ), 1, 3 ) || ')'
from L_AGENDA ax
where ax.codigo_agendamento = a.codigo_agendamento
and ax.encaixe = a.encaixe) data_view,
(select ax.data from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) data,
(select ax.codigo_posto from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_posto,
(select ax.codigo_sala from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_sala,
(select ax.de from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) de,
(select ax.ate from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) ate,
(select ax.flag_status from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) flag_status,
(select ax.codigo_funcionario from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_funcionario,
(select ax.codigo_exame from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_exame,
(select ax.codigo_convenio from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_convenio,
(select ax.nome from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) nome,
(select ax.sequencial_sala from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) sequencial_sala,
(select ax.encaixe from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) encaixe,
(select ax.observacao from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) observacao,
(select ax.telefone from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) telefone,
(select ax.codigo_agendamento from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) codigo_agendamento,
(select ax.matricula from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) matricula,
(select fs.descricao from L_I_FLAG_STATUS fs where fs.codigo = a.flag_status ) status,
(select s.descricao from L_SALA s where s.codigo_sala = a.codigo_sala) nome_sala,
(select u.nome from B_USUARIO u where u.codigo_usuario = a.codigo_funcionario) nome_funcionario,
(select au.codigo_usuario from L_AGENDA_USO au where au.codigo_agendamento = a.codigo_agendamento and au.encaixe = a.encaixe) em_uso,
(select ax.RESPOSTA_ESPECIAL from L_AGENDA ax where ax.codigo_agendamento = a.codigo_agendamento and ax.encaixe = a.encaixe) RESPOSTA_ESPECIAL
from L_AGENDA a
where a.CODIGO_POSTO = '01'
and a.DATA >= '04/14/2009 00:00:00'
and a.DATA <= '04/14/2009 23:59:59'
and a.codigo_sala = '01'
order by a.codigo_posto,a.codigo_sala,a.data,a.de,a.ate,a.sequencial_sala,a.encaixe
/// -------> Query B
select
SubStr(StrRepeat('0',4-StrLen(Trim(cast(de as char(4)))))||Trim(cast(de as char(4))),1,2) || ':' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(de as char(4)))))||Trim(cast(de as char(4))),3,2) || '-' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ate as char(4)))))||Trim(cast(ate as char(4))),1,2) || ':' ||
SubStr(StrRepeat('0',4-StrLen(Trim(cast(ate as char(4)))))||Trim(cast(ate as char(4))),3,2)
hora,
StrRepeat('0',2-StrLen(Trim( cast(extractday(data) as char(10)) )))||Trim( cast(extractday(data) as char(10)) ) || ' ' ||
SubStr ( ( case ExtractMonth(data)
when 1 then 'Janeiro'
when 2 then 'Fevereiro'
when 3 then 'Março'
when 4 then 'Abril'
when 5 then 'Maio'
when 6 then 'Junho'
when 7 then 'Julho'
when 8 then 'Agosto'
when 9 then 'Setembro'
when 10 then 'Outubro'
when 11 then 'Novembro'
when 12 then 'Dezembro'
end ), 1, 3 ) || ' ' ||
-- StrRepeat('0',4-StrLen(Trim( cast(extractyear(data) as char(10)) )))||Trim( cast(extractyear(data) as char(10)) ) || ' ' ||
'(' || SubStr ( ( case ExtractWeekDay(data)
when 0 then 'Domingo'
when 1 then 'Segunda'
when 2 then 'Terça'
when 3 then 'Quarta'
when 4 then 'Quinta'
when 5 then 'Sexta'
when 6 then 'Sábado'
end ), 1, 3 ) || ')' data_view ,
a.data ,
a.codigo_posto ,
a.codigo_sala ,
a.data ,
a.de ,
a.ate ,
a.flag_status ,
a.codigo_funcionario ,
a.codigo_exame ,
a.codigo_convenio ,
a.nome ,
a.sequencial_sala ,
a.encaixe ,
a.observacao ,
a.telefone ,
a.codigo_agendamento ,
a.matricula ,
(select fs.descricao from L_I_FLAG_STATUS fs where fs.codigo = a.flag_status ) status,
(select s.descricao from L_SALA s where s.codigo_sala = a.codigo_sala) nome_sala,
(select u.nome from B_USUARIO u where u.codigo_usuario = a.codigo_funcionario) nome_funcionario,
(select au.codigo_usuario from L_AGENDA_USO au where au.codigo_agendamento = a.codigo_agendamento and au.encaixe = a.encaixe) em_uso,
a.RESPOSTA_ESPECIAL
from L_AGENDA a
where a.CODIGO_POSTO = '01'
and a.DATA >= '04/14/2009 00:00:00'
and a.DATA <= '04/14/2009 23:59:59'
and a.codigo_sala = '01'
order by a.codigo_posto,a.codigo_sala,a.data,a.de,a.ate,a.sequencial_sala,a.encaixe