Subquerie

Tengo un sentencia SQL a Ejecutar en SQL Server 2000 que contiene una subconsulta simple del estilo SELECT DISTINCT t1. Campo1, t1.Campo2 FROM Demanda t1, DemQuejoso t2 WHERE t1.cveasunto=t2. Cveasunto AND t2. Quejoso IN (SELECT Quejoso FROM DemQuejoso WHERE NumRegistro=200200260), como veras es muy sencilla y funciona correctamente con pocos registros (Demanda 8500 y Quejoso 11500 regs.), pero cuando la probé con al base en producción con la tabla de Demanda alrededor de 95,000 regs. Y la de Quejoso contiene 134,000 regs. La consulta simplemente no responde, probé colocanto en una tabla temporal el resultado del SELECT externo y aplicar la misma sentencia solamente cambiando la Tabla Demanda por la Temporal, pero aún así espere mas de 20 minutos y no repondió (aún que en la temporal solamente contenía 516 regs.), de todos modos si me hubiera respondido SQL Server es inservible así, el tiempo de respuesta es muy alto para una validación que se hace en línea al momento de registrar una Demanda.
¿A qué crees que se deba?, digo, uno de ellos es la cantidad de registros pero aún así no me parece normal cuando apliqué la segunda alternativa. Y digamos que esto es simple porque la sentencia SQL se construye dinámicamente y puede estar relacionada la tabla demanda (master) a 'n' tablas de detalle (quejoso, autoridad, tercero perjudicado, etc) y donde cada una de detalle sería una subconsulta dentro del mismo SELECT.

2 respuestas

Respuesta
1
Aquí esta tu query:
SELECT
DISTINCT t1. Campo1, t1. Campo2
FROM Demanda t1, DemQuejoso t2
WHERE t1.cveasunto=t2.cveasunto
AND t2.Quejoso IN (SELECT Quejoso FROM DemQuejoso WHERE NumRegistro=200200260)
Ahora bien, yo te sugiero lo siguiente:
SELECT DISTINCT t1.Campo1, t1.Campo2
FROM Demanda t1
WHERE EXISTS(SELECT t2.Quejoso
FROM DemQuejoso t2
WHERE t1.cveasunto=t2.cveasunto
AND t2.NumRegistro=200200260)
Adicionalmente te comento que si sigue lento es por que necesitas crear el indice por la cveasunto de cada tabla, en ORACLE se puede (lo ignoro en SQL SERVER). Me había sucedido que unos procesos eran lentos con tablas de más de un millón de regs., como un promedio de más de media hora, pero al agregar los indices estos procesos se tardaron 5 minutos, ya que la búsqueda no se efectuaba secuencialmente sino por los indices...
Tu respuesta me parece muy buena y de verdad te agradezco me hayas respondido pero quiero aclarar algo.
En relación a lo que me comentaste de los índices ya los había creado pero me falto aclararte que precisamente el resultado de la consulta externa debe excluir al numregistro=200200260 es decir la sentencia debí haberla escrito como sigue:
SELECT
DISTINCT t1.Campo1,t1.Campo2
FROM Demanda t1,DemQuejoso t2
WHERE t1.cveasunto=t2.cveasunto
AND t2.Quejoso IN (SELECT Quejoso FROM DemQuejoso WHERE NumRegistro=200200260)
AND t2.numregistro<>200200260
Perdón por esta burrada de no incluirla completa.
En tal caso se complica la situación ya que en mi experiencia limitada he visto que los subquerys te alentan muchos procesos más con el distinct envuelto, pero espero te sirva lo siguiente:
SELECT
DISTINCT t1. Campo1, t1. Campo2
FROM Demanda t1, DemQuejoso t2
WHERE t1.cveasunto=t2.cveasunto
AND estaenlista(t2.Quejoso)=1
AND t2.numregistro<>200200260
Donde estaenlista es una unidad de programa que puede decir lo siguiente:
CREATE OR REPLACE FUNCTION estaenlista (bsca IN DemQuejoso.Quejoso%TYPE)
RETURN NUMBER
IS
loc NUMBER(1):=0;
CURSOR busca IS
SELECT 1
FROM DemQuejoso
WHERE Quejoso = bsca
AND NumRegistro=200200260;
BEGIN
OPEN busca;
FETCH busca INTO loc;
IF busca%NOTFOUND THEN
loc := 0;
ELSE
loc := 1;
END IF;
RETURN loc;
END;
Si puedes crear una unidad de programa entonces te sugiero que lo acupes, si vas ha crear un script (estaenlista.sql) con el contenido anterior te sugiero que al final de todo el texto pongas una diagonal (/) y lo ejecutes con start estaenlista y con esto te deberá crear la función en la base de datos.
También puedes evitarte usar la declaración del CURSOR y ser directo a partir del BEGIN usando:
SELECT quejoso FROM DemQuejoso
WHERE ...
IF SQL%NOTFOUND THEN
loc:=1;
END IF;
RETURN loc
Seria cuestión de que ahora tu le eches curiosidad...
Hasta luego y espero te sirva...
Respuesta
1
No soy ACruz, pero igual le mandaste tu pregunta a más de una persona ... pillín, je je.
Bueno, he miraro tu consulta y veo que accedes dos veces a la tabla DemQuejoso, una en la query principal, mediante join y luego en la subquery. Por lo general un IN suele ralentizar las respuestas, sobre todo si en la subquery no usas indices (cosa que desconozco por tu información), de todas formas, creo que una consulta simple como esta, que te envío podría ser tu solución..
SELECT DISTINCT t1.Campo1, t1.Campo2
FROM Demanda t1, DemQuejoso t2
WHERE t1.cveasunto=t2.cveasunto
and t2.NumRegistro=200200260
Ya me dirás
Suerte
Pablo
Una disculpa por la referencia a ACruz, efectivamente envíe a más de uno esta pregunta debido a que estoy un poco desesperado porque esta sentencia es la más simple que empleo en un algoritmo que requiero varias sentencias con subconsultas. Los índices ya los tengo creados. Otra cosa, se me olvidó aclarar lo siguiente:
El resultado de la consulta externa debe excluir al numregistro=200200260 es decir la sentencia debí haberla escrito como sigue:
SELECT
DISTINCT t1.Campo1,t1.Campo2
FROM Demanda t1,DemQuejoso t2
WHERE t1.cveasunto=t2.cveasunto
AND t2.Quejoso IN (SELECT Quejoso FROM DemQuejoso WHERE NumRegistro=200200260)
AND t2.numregistro<>200200260
Perdón por esta burrada de no incluirla completa.
Efectivamente en ese caso tienes que usar subquerys... y para evitar el IN puedes probar a usar un truquito que es el 0 = (select count(*) )
En tu caso sería algo así:
SELECT
DISTINCT t1. Campo1, t1. Campo2
FROM Demanda t1, DemQuejoso t2
WHERE t1.cveasunto=t2.cveasunto
AND 0 = (SELECT COUNT(*) FROM DemQuejoso D1 WHERE NumRegistro=200200260
AND D1.Quejoso= t2.Quejoso)
AND t2. Numregistro<>200200260
Suerte
Pablo

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas