Query complejo

28/09/2006 - 18:56 por Xtian | Informe spam
Creo que mi anterior mensaje no llego, aca lo repito ...

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 similare

Leer las respuestas

#1 Pablo Garateguy
28/09/2006 - 20:35 | Informe spam
Te paso los comentarios que agregué en el otro post (si llegó)

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:

Creo que mi anterior mensaje no llego, aca lo repito ...

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

Respuesta Responder a este mensaje
#2 Xtian
28/09/2006 - 21:29 | Informe spam
Gracias Pablo por las recomendaciones, a ver vayamos por partes

-gd.guia_det_cus no tiene un indice en la tabla y en realidad no se si lo
deba tener y es que te comento que la tabla tendra unas 50 columnas o mas y
si bien esta consulta es importante no se si amerite o si es sumamente
necesario crearle un indice al campo; de hacerlo y seguir los pasos que me
dices, que tendria que hacer? un "or" o un "union"? a eso te refieres con
dividir la consulta?

-Si he generado el plan de ejecución y si bien es bastante grande al parecer
usa los indices que tengo, pero igual no me estan solucionando el problema al
parecer.

-El volumen de datos es pequeño para este query unos 50 datos a lo maximo,
aunque como te explico este es la base para otros querys mas complejos que
devuelven mas data

De nuevo muchas gracias por la ayuda y espero que me puedan ir dando mas
sugerencias por favor.

Saludos cordiales

"Pablo Garateguy" wrote:

Te paso los comentarios que agregué en el otro post (si llegó)

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:

> Creo que mi anterior mensaje no llego, aca lo repito ...
>
> 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
>
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaRespuesta Tengo una respuesta
Search Busqueda sugerida