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

Preguntas similare

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


Respuesta Responder a este mensaje
#2 Mauricio Pulla
28/09/2006 - 22:03 | Informe spam
Hola xtian.

La complejida de tu query se debe al diseño de tu base de datos.

El diseño de base de datos no es de lo mejor, en lo personal si estubiera en
etapa de desarrollo, pensaria en tratar de restructurarla, si no es posible
trataria de crear claves artificiales simples a las diferentes tablas para
no usar llaves compuestas, en las conbinaciones.

Existe un buen articulo de Carlos Sacristán llamado "Claves naturales o
artificiales", espero te sea de utilidad.

Saludos.
Mauricio Pulla.
Cuenca-Ecuador.


"xtian" escribió en el mensaje
news:
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
#3 Xtian
28/09/2006 - 23:11 | Informe spam
Gracias Mauricio, de verdad tenia algo de eso presente siempre, pero no es
sino hasta este momento en el que estoy evaluando si puede ser la mejor
solución, de todas formas hare las pruebas en el servidor de pruebas y
veremos como resulta.
De todas formas si alguien tiene mas sugerencias seran bienvenidas

Muchas gracias

"Mauricio Pulla" wrote:

Hola xtian.

La complejida de tu query se debe al diseño de tu base de datos.

El diseño de base de datos no es de lo mejor, en lo personal si estubiera en
etapa de desarrollo, pensaria en tratar de restructurarla, si no es posible
trataria de crear claves artificiales simples a las diferentes tablas para
no usar llaves compuestas, en las conbinaciones.

Existe un buen articulo de Carlos Sacristán llamado "Claves naturales o
artificiales", espero te sea de utilidad.

Saludos.
Mauricio Pulla.
Cuenca-Ecuador.


"xtian" escribió en el mensaje
news:
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
#4 Xtian
29/09/2006 - 17:59 | Informe spam
Hola de nuevo, ayer cree una clave artificial para un par de mis tablas, lo
hice de la siguiente manera:
a) Cree un campo identity en la tabla guia_courier, la cual indexe
b) Cree un campo entero en la tabla guia_detalle_courier el cual tambien
indexe.
c) Replique los valores de a) en b)

Inmediatamente compare dos querys y me arrojaron los siguientes resultados
1.Consulta usando la llave natural:
declare @anio char(4)
declare @anio_ant char(4)

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

select gd.guia_det_nro
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
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

cuyo resultado tomo 6 segundos y plan de ejecución:

|--Hash Match(Inner Join, HASH:([gd].[GUIA_ANO],
[gd].[GUIA_NRO])=([g].[GUIA_ANO], [g].[GUIA_NRO]),
RESIDUAL:([gd].[GUIA_ANO]=[g].[GUIA_ANO] AND
[gd].[GUIA_NRO]=[g].[GUIA_NRO]))
|--Index
Seek(OBJECT:([scharff2].[dbo].[GUIA_DETALLE_COURIER].[IX_GUIA_MAX] AS [gd]),
SEEK:([gd].[EMPR_COD]='00000081' AND [gd].[SUC_COD]='PELIM01' AND
[gd].[UNI_NEG_COD]='CRI' AND [gd].[PRO_COD]='INB' AND [gd].[GUIA_ANO] >=
[@anio_ant] AND [gd].[GUIA_ANO] <= [@anio]) ORDERED FORWARD)
|--Index
Seek(OBJECT:([scharff2].[dbo].[GUIA_COURIER].[GUIA_COURIER_EMP_SUC_UDN_PROD_FK]
AS [g]), SEEK:([g].[EMPR_COD]='00000081' AND [g].[SUC_COD]='PELIM01' AND
[g].[UNI_NEG_COD]='CRI' AND [g].[PRO_COD]='INB') ORDERED FORWARD)

2. Consulta usando la llave artificial:

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

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

select gd.guia_det_nro
from guia_courier g
inner join guia_detalle_courier gd
on g.guia_key = gd.guia_key
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

usando como join el nuevo campo creado, pero que demora un poco mas, 7 a 10
segundos y com el plan de ejecucion:

|--Parallelism(Gather Streams)
|--Hash Match(Inner Join, HASH:([gd].[GUIA_KEY])=([g].[GUIA_KEY]),
RESIDUAL:([gd].[GUIA_KEY]=[g].[GUIA_KEY]))
|--Bitmap(HASH:([gd].[GUIA_KEY]), DEFINE:([Bitmap1002]))
| |--Parallelism(Repartition Streams, PARTITION
COLUMNS:([gd].[GUIA_KEY]))
| |--Clustered Index
Seek(OBJECT:([scharff2].[dbo].[GUIA_DETALLE_COURIER].[PK_GUIA_DETALLE_COURIER]
AS [gd]), SEEK:([gd].[EMPR_COD]='00000081' AND [gd].[SUC_COD]='PELIM01' AND
[gd].[UNI_NEG_COD]='CRI' AND [gd].[PRO_COD]='INB' AND [gd].[GUIA_ANO] >=
[@anio_ant] AND [gd].[GUIA_ANO] <= [@anio]) ORDERED FORWARD)
|--Parallelism(Repartition Streams, PARTITION
COLUMNS:([g].[GUIA_KEY]), WHERE:(PROBE([Bitmap1002])=TRUE))
|--Index
Scan(OBJECT:([scharff2].[dbo].[GUIA_COURIER].[IX_GUIA_KEY] AS [g]))

Esperaba un incremento dramatico en la velocidad de esta consulta pero no lo
veo asi, puedo estar fallando en algo? gracias por sus comentarios, y sus
sugerencias.

Saludos


"Xtian" wrote:

Gracias Mauricio, de verdad tenia algo de eso presente siempre, pero no es
sino hasta este momento en el que estoy evaluando si puede ser la mejor
solución, de todas formas hare las pruebas en el servidor de pruebas y
veremos como resulta.
De todas formas si alguien tiene mas sugerencias seran bienvenidas

Muchas gracias

"Mauricio Pulla" wrote:

> Hola xtian.
>
> La complejida de tu query se debe al diseño de tu base de datos.
>
> El diseño de base de datos no es de lo mejor, en lo personal si estubiera en
> etapa de desarrollo, pensaria en tratar de restructurarla, si no es posible
> trataria de crear claves artificiales simples a las diferentes tablas para
> no usar llaves compuestas, en las conbinaciones.
>
> Existe un buen articulo de Carlos Sacristán llamado "Claves naturales o
> artificiales", espero te sea de utilidad.
>
> Saludos.
> Mauricio Pulla.
> Cuenca-Ecuador.
>
>
> "xtian" escribió en el mensaje
> news:
> 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