SQL Server - Alternativas para agilizar consulta...

Asked By Francisco on 04-Jun-08 09:13 PM
Que tal Sres. tengo una tabla de aprox 5 millones de reg. y en dicha tabla
existe un campo 'codnivel' Char(20). Ejem: 020103050705...... Los 2
primeros(02), los 2 siguientes (01) y asi sucesivamente tienen un
significado. Ahora el campo tiene su indice y debo extraer informacion de
cualquier lugar de la cadena. Ejem:

Caso 1:
SELECT <campos>
FROM mytabla
WHERE LEFT(codnivel,2) IN ('01','02','03'..)  --Esta consulta es lentisimo
se agilizar 3 veces puesto que si hace uso del indice. Pero aun asi siento
que es lento. He probado con los operadores y funciones conocidas pero no
logro agilizarlo mas....alguna sugerencia ???

Caso 2 (el mas usado)
SELECT <campos>
FROM mytabla
WHERE SUBSTRING(codnivel,5,2) IN ('03','04','07'...)  --Esto es mas lento
todavia

Si hago uso del LEFT, SUBSTRING, IN ú otras funciones, la consulta es lenta
porque me parece que no hace uso del indice. Pero si utilizo el campo solo
sin nada que lo envuelva entonces es una bala la consulta. ¿Algunas
alternativas de como extraer la informacion de forma rapida ?..gracias.




Sergio E. replied on 04-Jun-08 10:09 PM
no se mucho de esto pero, ¿no te valdria crearte un indice para cada
substring?
algo como un indice para substring(codnivel,5,2), otro apra
substring(codnivel 1,2) etc?

Saludos
Sergio E.
Pablo Roca replied on 05-Jun-08 04:00 AM
Hola Francisco,

De entrada te recomiendo que te crees dos campos calculados (persistentes)
por cada uno de esos dos substrings.

Crea un indice para cada uno de ellos y vuelve a probar las consultas. Ya
nos dirás.

No entiendo como haces un LIKE '01%' si lo que vas a mirar es a nivel de dos
digitos, quitale ese %

Si lo haces  (codnivel LIKE '01%' Or codnivel LIKE '02') . El LIKE es para
busquedas por contenido, cosa que no tiene sentido en el ejemñp que
planteas.

Yo prefiero hacerlo así:

(codnivel = '01' Or codnivel = '02' ...)

--

Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com
Pablo Roca replied on 05-Jun-08 04:03 AM
Ah, de paso que los haces así .. pues es muy posible que te vayan mejor
pasandolos a int y realizando las consultas como int

--

Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com
GuxMV replied on 05-Jun-08 09:45 AM
No es posible crear indices para expresiones. Los indices se crean sobre
listas de columnas de las tablas.

--
Gustavo Larriera, Microsoft MVP
https://mvp.support.microsoft.com/profile/gustavo.larriera
--
Este mensaje se proporciona tal como es, sin garantías de ninguna clase.
GuxMV replied on 05-Jun-08 09:51 AM
En una columna de caracteres indizada, las búsquedas por fragmentos internos
o hacia la derecha de la columna no aprovecha la existencia de índices, por
lo que el rendimiento es malo. Las búsquedas por los primeros caracteres
desde la izquierda sí logran un rendimiento mejor.

Si usted está a tiempo puede hacer un mejor diseño: Si la columna es un
string cuyas subpartes tienen información propia, entonces deberían ser
columnas separadas.

Desde el punto de vista de la teoría, cada columna debe almacenar un valor
atómico cosa que usted no está haciendo.

--
Gustavo Larriera, Microsoft MVP
https://mvp.support.microsoft.com/profile/gustavo.larriera
--
Este mensaje se proporciona tal como es, sin garantías de ninguna clase.
Francisco replied on 05-Jun-08 11:24 AM
Gracias por sus sugerencias. No puedo agregar columnas a dicha tabla, pues
son de un proveedor externo y por contrato ninguna tabla debe ser alterada
en su integridad.  Sigo haciendo pruebas y luego les comentare el resultado.
gracias a todos...


dos
Victor Koch replied on 05-Jun-08 11:32 AM
Hola,

Eso no quita que podes tener una tabla secundaria que se relacione con la
tabla principal y generar un trigger para que se actualice la tabla
secundaria.
Este cambio o agregado en el diseño no altera la integridad.

--
Un Saludo, Víctor Koch
Penta replied on 08-Jun-08 06:52 AM
Siiii, me sumo a lo indicado por Victor.
Podrias tener un tabla que se actualice con Trigger en dicha tbala
podria tener:
codnivel Char(20).
Nivel1 varchar(xx)
Nivel2 varchar(xx)

Indices por Nivel1 y Nivel 2 y  Join con tu tabla con codnivel

Atte.
Penta.
Francisco replied on 05-Jun-08 01:17 PM
En verdad les agradesco sus alternativas. Es una alternativa que lo consulte
antes de efectuarlo y que creen....pues nada de nada, se oponen totalmente a
que haga algo en su base de datos. Mas tarde tendre reunion con gerencia
para analizar este tema...gracias por todo....
Sergio E. replied on 05-Jun-08 02:51 PM
Si no puedes tocar SU base de datos, supongo que si puedes crearte una
propia, y en ella crear la tabla que necesitas y mediante un trigger
actualizarla desde la base de la compañia externa... estoy suponiendo que la
base de datos si esta en un servidor tuyo...

y por lo que tengo entendido puedes hacer select campos from
basededatos.esquema.tabla

Saludos
Sergio E.
Penta replied on 08-Jun-08 06:52 AM
Estimado Sergio E.
Pero si como dice Francisco NO puede tocar la base de datos, como hara
el trigger ?

Yo optaria por tocar la BD si o si, pues que el trigger lo ejecute la
empresa(no deberia cobrar por esto)  si se quiere quedar tranquila.

Solo lo estan haciendo para ganarse unas monedas de mas.

Atte.
Penta.
Sergio E. replied on 05-Jun-08 08:31 PM
A  ver tal vez me equivoque de termino (trigger), y lo entiendo asi:

Yo tengo un servidor de base de datos, con una base que ya esta en
produccion... esa es INTOCABLE (sea baseA), pero está en mi equipo, asi que
en ese mismo servidor e instancia, creo otra nueva base de datos (BaseB)..
con las tablas que necesito...
en la baseA no hago nada, y en la baseB creo un procedimiento que se ejecute
por decir, todas las noches a las 4 am, que haga algo como esto:

insert into baseb.dbo.tablamia select substring(codigo,1,2) as c1,
substring(codigo,3,2) as c2 from basea.dbo.tablacodigos

con lo que no toco la baseA y genero mi tabla necesaria para mi aplicacion

Saludos
Penta replied on 08-Jun-08 06:53 AM
A pues eso si estimado Sergio E.
Pero con eso no solucionamos el problema de Francisco de modo de
agilizar la consulta, No veo porque motivo Francisco no tiene acceso a
crear una tablita al menos en esa BD y realizando el Job como tu
planteas no sera necesario crear el Trigger.

Repito:
podria tener:
codnivel Char(20).
Nivel1 varchar(xx)
Nivel2 varchar(xx)
Indices por Nivel1 y Nivel 2 y  Join con tu tabla con codnivel "

En vez del trigger que lo haga con un JOB no sera on line pero no
sabemos si le servira asi o no, si lo quiere on line insisto con el
trigger.

Atte.
Penta.