Query complejo

28/09/2006 - 16:52 por xtian | Informe spam
Hola amigos del grupo
Estoy un poco preocupado, tengo un query que me toma mas de un minuto y
tengo como tarea optimizarlo, ya que este es la base de otros querys un
poco mas complejos, el query es el siguiente:

declare @anio char(4)
declare @anio_ant char(4)

set @anio = datepart(yy, getdate())
set @anio_ant = datepart(yy, getdate()) - 1

select oa.ord_ano + ' - ' + oa.ord_nro Orden_Trabajo,
isnull(gd.mft_ano, '') + ' - ' + isnull(gd.mft_nro, '')
Manifiesto,
gd.guia_det_nro Guia,
case rtrim(isnull(gd.guia_det_con_cia, ''))
when '' then rtrim(isnull(gd.guia_det_con_nom, ''))
else rtrim(isnull(gd.guia_det_con_cia, ''))
end Consignatario,
isnull(convert(char(10),oa.fech_ord,103), '') Fch_Orden,
isnull(nd.not_det_obs, '') Descripcion_Notificacion,
c2.cal_id_dom - c1.cal_id_dom DT,
isnull(e1.emp_abr, '') Tecnico,
isnull(e2.emp_abr, '') Generado,
isnull(gd.guia_det_cus,'') CustomerCod,
isnull(oa.emp_cod_tec, '') TecnicoCod,
isnull(gd.guia_det_con_cod, '') Cliente,
isnull(g.guia_bill_imp, '') TipoPago,
oa.fech_ord Ordenacion
from guia_courier g
inner join guia_detalle_courier gd
on g.empr_cod = gd.empr_cod and
g.suc_cod = gd.suc_cod and
g.uni_neg_cod = gd.uni_neg_cod and
g.pro_cod = gd.pro_cod and
g.guia_ano = gd.guia_ano and
g.guia_nro = gd.guia_nro and
not exists ( select 'x'
from volante_almacen v
where v.empr_cod = gd.empr_cod and
v.suc_cod = gd.suc_cod and
v.uni_neg_cod = 'TMP' and
gd.uni_neg_cod = 'CRI' and
v.pro_cod = 'TMP' and
gd.pro_cod = 'INB' and
v.otm_ano = gd.mft_ano and
v.otm_nro = gd.mft_nro and
v.otm_det_nro = gd.guia_det_nro)
and
not exists ( select 'x'
from orden_salida_detalle_terminal os
where os.empr_cod = gd.empr_cod and
os.suc_cod = gd.suc_cod and
os.uni_neg_cod = 'TMP' and
gd.uni_neg_cod = 'CRI' and
os.pro_cod = 'TMP' and
gd.pro_cod = 'INB' and
os.osdt_ano = gd.mft_ano and
os.osdt_nro = gd.mft_nro and
os.osdt_det_nro = gd.guia_det_nro)
inner join orden_aduana oa
on gd.empr_cod = oa.empr_cod and
gd.suc_cod = oa.suc_cod and
gd.uni_neg_cod = oa.uni_neg_cod and
gd.pro_cod = oa.pro_cod and
gd.guia_ano = oa.guia_ano and
gd.guia_nro = oa.guia_nro and
gd.guia_det_nro = oa.guia_det_nro
inner join empleado e1
on e1.emp_cod = oa.emp_cod_tec
inner join calendario c1
on c1.cal_fecha = cast(convert(char(10),oa.fech_ord,103)
as datetime)
inner join calendario c2
on c2.cal_fecha = cast(convert(char(10),getdate(),103)
as datetime)
inner join notificacion n
on oa.empr_cod = n.empr_cod and
oa.suc_cod = n.suc_cod and
oa.uni_neg_cod = n.uni_neg_cod and
oa.pro_cod = n.pro_cod and
oa.guia_ano = n.guia_ano and
oa.guia_nro = n.guia_nro and
oa.guia_det_nro = n.guia_det_nro and
oa.ord_ano = n.ord_ano and
oa.ord_nro = n.ord_nro
inner join notificacion_detalle nd
on n.empr_cod = nd.empr_cod and
n.suc_cod = nd.suc_cod and
n.uni_neg_cod = nd.uni_neg_cod and
n.pro_cod = nd.pro_cod and
n.ord_ano = nd.ord_ano and
n.ord_nro = nd.ord_nro and
n.not_ano = nd.not_ano and
n.not_nro = nd.not_nro
inner join empleado e2
on e2.emp_cod = nd.not_det_usu_crea
where gd.empr_cod = '00000081' and
gd.suc_cod = 'PELIM01' and
gd.uni_neg_cod = 'CRI' and
gd.pro_cod = 'INB' and
gd.guia_ano between @anio_ant and @anio and
isnull(gd.guia_det_cus, '') = '' and
nd.not_det_sta = '0616'
order by oa.fech_ord, gd.guia_det_nro asc

A ver, unos datos, los campos que conforman los joins en su mayoria
tienen indices y las tablas tienen llaves compuestas. Por ejemplo la
tabla guia_courier tiene como llave(empr_cod, suc_cod, uni_neg_cod,
pro_cod, guia_ano, guia_nro) las columnas en estos casos son de tipo
char con una longitud determinada; se que esta información no es
suficiente para que me puedan dar una recomendación, se que me van a
pedir que les muestre el plan de ejecución y estadisticas, asi que se
los pasare en la medida que me expliquen que es lo que van a necesitar.

Asi mismo tengo otra duda y es que cuando corro el query aislado(SET
TRANSACTION ISOLATION READ UNCOMMITTED) obtengo tiempos variados entre
mis ejecuciones, lo cual me llena de dudas pues supuestamente de esta
manera me estoy librando de los bloqueos que puedan existir y en teoria
mi query deberia correr en un tiempo medio pero no es siempre asi a
veces corre rápidamente y en otros casos muy lento.

Estare atento a las solicitudes que me hagan y a las recomendaciones
que surjan de esto, se los agradecere enormemente

Muchas gracias
 

Leer las respuestas

#1 Pablo Garateguy
28/09/2006 - 17:47 | Informe spam
Te mando algunas recomendaciones y comentarios para que tengas en cuenta:

- El uso de funciones dentro del where impide que se utilicen índices, dado
que al momento de ejecutarlo, el motor no puede determinar el valor del campo
isnull(gd.guia_det_cus, '') = '', puede llegar a convenirte separar esta
consulta en 2 (una asumiendo que es null y otra asumiendo que no).

- Lo ideal es que ejecutes es que obtengas el plan de ejecución para que
veas si está usando correctamente los índices que tienes definidos.

- No sé el volumen de datos que estás devolviendo, pero si son muchos, el
agregar el Order By genera bastante overhead en el servidor; podrías evaluar
efectuar este ordenamiento desde la aplicación (siempre que uses una
aplicación cliente y sea posible hacerlo ahí)


Saludos
Pablo Garateguy
MCP - Visual Basic 6


"xtian" wrote:

Hola amigos del grupo
Estoy un poco preocupado, tengo un query que me toma mas de un minuto y
tengo como tarea optimizarlo, ya que este es la base de otros querys un
poco mas complejos, el query es el siguiente:

declare @anio char(4)
declare @anio_ant char(4)

set @anio = datepart(yy, getdate())
set @anio_ant = datepart(yy, getdate()) - 1

select oa.ord_ano + ' - ' + oa.ord_nro Orden_Trabajo,
isnull(gd.mft_ano, '') + ' - ' + isnull(gd.mft_nro, '')
Manifiesto,
gd.guia_det_nro Guia,
case rtrim(isnull(gd.guia_det_con_cia, ''))
when '' then rtrim(isnull(gd.guia_det_con_nom, ''))
else rtrim(isnull(gd.guia_det_con_cia, ''))
end Consignatario,
isnull(convert(char(10),oa.fech_ord,103), '') Fch_Orden,
isnull(nd.not_det_obs, '') Descripcion_Notificacion,
c2.cal_id_dom - c1.cal_id_dom DT,
isnull(e1.emp_abr, '') Tecnico,
isnull(e2.emp_abr, '') Generado,
isnull(gd.guia_det_cus,'') CustomerCod,
isnull(oa.emp_cod_tec, '') TecnicoCod,
isnull(gd.guia_det_con_cod, '') Cliente,
isnull(g.guia_bill_imp, '') TipoPago,
oa.fech_ord Ordenacion
from guia_courier g
inner join guia_detalle_courier gd
on g.empr_cod = gd.empr_cod and
g.suc_cod = gd.suc_cod and
g.uni_neg_cod = gd.uni_neg_cod and
g.pro_cod = gd.pro_cod and
g.guia_ano = gd.guia_ano and
g.guia_nro = gd.guia_nro and
not exists ( select 'x'
from volante_almacen v
where v.empr_cod = gd.empr_cod and
v.suc_cod = gd.suc_cod and
v.uni_neg_cod = 'TMP' and
gd.uni_neg_cod = 'CRI' and
v.pro_cod = 'TMP' and
gd.pro_cod = 'INB' and
v.otm_ano = gd.mft_ano and
v.otm_nro = gd.mft_nro and
v.otm_det_nro = gd.guia_det_nro)
and
not exists ( select 'x'
from orden_salida_detalle_terminal os
where os.empr_cod = gd.empr_cod and
os.suc_cod = gd.suc_cod and
os.uni_neg_cod = 'TMP' and
gd.uni_neg_cod = 'CRI' and
os.pro_cod = 'TMP' and
gd.pro_cod = 'INB' and
os.osdt_ano = gd.mft_ano and
os.osdt_nro = gd.mft_nro and
os.osdt_det_nro = gd.guia_det_nro)
inner join orden_aduana oa
on gd.empr_cod = oa.empr_cod and
gd.suc_cod = oa.suc_cod and
gd.uni_neg_cod = oa.uni_neg_cod and
gd.pro_cod = oa.pro_cod and
gd.guia_ano = oa.guia_ano and
gd.guia_nro = oa.guia_nro and
gd.guia_det_nro = oa.guia_det_nro
inner join empleado e1
on e1.emp_cod = oa.emp_cod_tec
inner join calendario c1
on c1.cal_fecha = cast(convert(char(10),oa.fech_ord,103)
as datetime)
inner join calendario c2
on c2.cal_fecha = cast(convert(char(10),getdate(),103)
as datetime)
inner join notificacion n
on oa.empr_cod = n.empr_cod and
oa.suc_cod = n.suc_cod and
oa.uni_neg_cod = n.uni_neg_cod and
oa.pro_cod = n.pro_cod and
oa.guia_ano = n.guia_ano and
oa.guia_nro = n.guia_nro and
oa.guia_det_nro = n.guia_det_nro and
oa.ord_ano = n.ord_ano and
oa.ord_nro = n.ord_nro
inner join notificacion_detalle nd
on n.empr_cod = nd.empr_cod and
n.suc_cod = nd.suc_cod and
n.uni_neg_cod = nd.uni_neg_cod and
n.pro_cod = nd.pro_cod and
n.ord_ano = nd.ord_ano and
n.ord_nro = nd.ord_nro and
n.not_ano = nd.not_ano and
n.not_nro = nd.not_nro
inner join empleado e2
on e2.emp_cod = nd.not_det_usu_crea
where gd.empr_cod = '00000081' and
gd.suc_cod = 'PELIM01' and
gd.uni_neg_cod = 'CRI' and
gd.pro_cod = 'INB' and
gd.guia_ano between @anio_ant and @anio and
isnull(gd.guia_det_cus, '') = '' and
nd.not_det_sta = '0616'
order by oa.fech_ord, gd.guia_det_nro asc

A ver, unos datos, los campos que conforman los joins en su mayoria
tienen indices y las tablas tienen llaves compuestas. Por ejemplo la
tabla guia_courier tiene como llave(empr_cod, suc_cod, uni_neg_cod,
pro_cod, guia_ano, guia_nro) las columnas en estos casos son de tipo
char con una longitud determinada; se que esta información no es
suficiente para que me puedan dar una recomendación, se que me van a
pedir que les muestre el plan de ejecución y estadisticas, asi que se
los pasare en la medida que me expliquen que es lo que van a necesitar.

Asi mismo tengo otra duda y es que cuando corro el query aislado(SET
TRANSACTION ISOLATION READ UNCOMMITTED) obtengo tiempos variados entre
mis ejecuciones, lo cual me llena de dudas pues supuestamente de esta
manera me estoy librando de los bloqueos que puedan existir y en teoria
mi query deberia correr en un tiempo medio pero no es siempre asi a
veces corre rápidamente y en otros casos muy lento.

Estare atento a las solicitudes que me hagan y a las recomendaciones
que surjan de esto, se los agradecere enormemente

Muchas gracias


Preguntas similares