Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Dudas con esta consulta (https://www.clubdelphi.com/foros/showthread.php?t=85863)

Caminante 16-05-2014 13:44:04

Dudas con esta consulta
 
Buenos dias, tardes o noches segun corresponda. Tengo una duda que espero puedan ayudarme a despejar.
Tengo un sistema funcionando en firebird 2.5. En este tengo un listado de resumen. La consulta que lanzo es la siguiente:

Código SQL [-]
SELECT MC.ID_MOV, DC.ID_DETCIL, MC.FECHADOC, DC.CIL,CI.TIPOGASID, TG.TIPOGAS,
CI.DESCRIPCION,CI.CAPACIDAD, MC.SERIE, MC.DOCUMENTO,DC.PLAZO,
DC.FECHADEV, DC.DOCDEV,MC.NOMDESTINO, CP1.NOMBRE,CP2.ID_CLIENTE,
CP2.TIPO, CP2.NOMBRE,DC.LUGAR, DC.OBSERVACION FROM
DETALLECIL DC INNER JOIN MOVCILINDROS MC ON DC.MOVCIL=MC.ID_MOV
INNER JOIN CILINDROS CI on DC.CIL=CI.ID_CILINDRO INNER JOIN
CLIEPROV CP1 ON MC.NOMDESTINO=CP1.ID_CLIENTE INNER JOIN
CLIEPROV CP2 ON CI.PROPIETARIO=CP2.ID_CLIENTE
INNER JOIN TIPOGASES TG ON CI.tipogasid=TG.id
WHERE CP1.id_cliente>0
La consulta en si me da los resultados esperados con una demora maxima de un par de segundos. Ahora revisando en los foros escuche mencionar el IB plan analizer para analizar las consultas. Lo probe y me salio en las tablaS MOVCILINDROS Y DETALLECIL una advertencia. Revisando veo que utiliza los indices que corresponde a sus respectivas claves foraneas.
Este es el plan usado:

Código SQL [-]
PLAN JOIN (CP1 INDEX (RDB$PRIMARY2), MC INDEX (RDB$FOREIGN5), DC INDEX (RDB$FOREIGN12), CI INDEX (RDB$PRIMARY1), CP2 INDEX (RDB$PRIMARY2), TG INDEX (PK_TIPOGASES))

Estas son las tablas usadas:

Código SQL [-]
CREATE TABLE CILINDROS (
    ID_CILINDRO  INTEGER NOT NULL,
    DESCRIPCION  VARCHAR(30),
    TIPOGASID    INTEGER NOT NULL,
    CAPACIDAD    VARCHAR(7),
    PROPIETARIO  INTEGER,
    OBSCILINDRO  VARCHAR(30)
);

CREATE TABLE CLIEPROV (
    ID_CLIENTE  INTEGER NOT NULL,
    RUC         VARCHAR(11),
    NOMBRE      TCADENA NOT NULL COLLATE ES_ES_CI_AI,
    EMAIL       VARCHAR(30),
    WEB         VARCHAR(30),
    CONTACTO    VARCHAR(50),
    TIPO        INTEGER NOT NULL,
    NOMMAYUS    TCADENA COLLATE ES_ES_CI_AI,
    RUBRO       TRUBRO NOT NULL
);

CREATE TABLE DETALLECIL (
    ID_DETCIL    INTEGER NOT NULL,
    MOVCIL       INTEGER NOT NULL,
    CIL          INTEGER NOT NULL,
    PLAZO        INTEGER DEFAULT 0,
    FECHADEV     DATE,
    OBSERVACION  VARCHAR(50),
    DOCDEV       VARCHAR(15),
    LUGAR        VARCHAR(15)
);

CREATE TABLE MOVCILINDROS (
    ID_MOV      INTEGER NOT NULL,
    NOMDESTINO  INTEGER NOT NULL,
    SERIE       VARCHAR(3) NOT NULL,
    DOCUMENTO   VARCHAR(10) NOT NULL,
    FECHADOC    DATE NOT NULL,
    VENDEDOR    INTEGER NOT NULL
);

CREATE TABLE TIPOGASES (
    ID       INTEGER NOT NULL,
    TIPOGAS  VARCHAR(10) NOT NULL COLLATE ES_ES_CI_AI
);

ALTER TABLE CILINDROS ADD PRIMARY KEY (ID_CILINDRO);
ALTER TABLE CLIEPROV ADD PRIMARY KEY (ID_CLIENTE);
ALTER TABLE DETALLECIL ADD PRIMARY KEY (ID_DETCIL);
ALTER TABLE MOVCILINDROS ADD PRIMARY KEY (ID_MOV);
ALTER TABLE TIPOGASES ADD CONSTRAINT PK_TIPOGASES PRIMARY KEY (ID);

ALTER TABLE CILINDROS ADD CONSTRAINT FK_CILINDROS_1 FOREIGN KEY (TIPOGASID) REFERENCES TIPOGASES (ID) ON UPDATE CASCADE;
ALTER TABLE CILINDROS ADD FOREIGN KEY (PROPIETARIO) REFERENCES CLIEPROV (ID_CLIENTE) ON DELETE NO ACTION ON UPDATE CASCADE;
ALTER TABLE DETALLECIL ADD CONSTRAINT FKDETALLECIL_CIL FOREIGN KEY (CIL) REFERENCES CILINDROS (ID_CILINDRO) ON DELETE NO ACTION ON UPDATE CASCADE;
ALTER TABLE DETALLECIL ADD FOREIGN KEY (MOVCIL) REFERENCES MOVCILINDROS (ID_MOV) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE MOVCILINDROS ADD CONSTRAINT FK_MOVCILINDROS_DEST FOREIGN KEY (NOMDESTINO) REFERENCES CLIEPROV (ID_CLIENTE) ON DELETE NO ACTION ON UPDATE CASCADE;
ALTER TABLE MOVCILINDROS ADD FOREIGN KEY (VENDEDOR) REFERENCES PERSONAL (ID_PERSONAL) ON DELETE NO ACTION ON UPDATE CASCADE;
Si bien la consulta no es lenta (Al menos no mucho). Me preocupa que no este debidamente optimizada. Viendo las estadisticas de los indices se muestra la siguiente selectividad:

RDB$FOREIGN5 24.59
RDB$FOREIGN12 2.48

Me pregunto ¿De que manera se puede mejorar esta consulta?

Gracias por la atención prestada...

duilioisola 16-05-2014 14:13:38

Dado que el WHERE actúa sobre la tabla "CLIEPROV CP1" yo trataría de empezar por ahí las uniones con las otras tablas.

Código SQL [-]
SELECT MC.ID_MOV, DC.ID_DETCIL, MC.FECHADOC, DC.CIL,CI.TIPOGASID, TG.TIPOGAS,
CI.DESCRIPCION,CI.CAPACIDAD, MC.SERIE, MC.DOCUMENTO,DC.PLAZO,
DC.FECHADEV, DC.DOCDEV,MC.NOMDESTINO, CP1.NOMBRE,CP2.ID_CLIENTE,
CP2.TIPO, CP2.NOMBRE,DC.LUGAR, DC.OBSERVACION
FROM
CLIEPROV CP1
JOIN MOVCILINDROS MC ON MC.NOMDESTINO=CP1.ID_CLIENTE
JOIN DETALLECIL DC ON DC.MOVCIL=MC.ID_MOV
JOIN CILINDROS CI ON DC.CIL=CI.ID_CILINDRO
JOIN CLIEPROV CP2 ON CI.PROPIETARIO=CP2.ID_CLIENTE
JOIN TIPOGASES TG ON CI.tipogasid=TG.id
WHERE
CP1.ID_CLIENTE > 0

Además de esto probaría la consulta utilizando LEFT JOIN.


Los índices que utiliza aparentemente son los correctos y parecen óptimos.
Código SQL [-]
CLIEPROV CP1
JOIN MOVCILINDROS MC ON MC.NOMDESTINO=CP1.ID_CLIENTE
ALTER TABLE MOVCILINDROS ADD CONSTRAINT FK_MOVCILINDROS_DEST FOREIGN KEY (NOMDESTINO) REFERENCES CLIEPROV (ID_CLIENTE) ON DELETE NO ACTION ON UPDATE CASCADE;
y
Código SQL [-]
JOIN DETALLECIL DC ON DC.MOVCIL=MC.ID_MOV
ALTER TABLE DETALLECIL ADD FOREIGN KEY (MOVCIL) REFERENCES MOVCILINDROS (ID_MOV) ON DELETE CASCADE ON UPDATE CASCADE;

Caminante 16-05-2014 16:57:43

Hola gracias por responder
Cita:

Empezado por duilioisola (Mensaje 476532)
Además de esto probaría la consulta utilizando LEFT JOIN.

Y Como seria la consulta??

He probado asi:

Código SQL [-]
SELECT MC.ID_MOV, DC.ID_DETCIL, MC.FECHADOC, DC.CIL,CI.TIPOGASID, TG.TIPOGAS,
CI.DESCRIPCION,CI.CAPACIDAD, MC.SERIE, MC.DOCUMENTO,DC.PLAZO,
DC.FECHADEV, DC.DOCDEV,MC.NOMDESTINO, CP1.NOMBRE,CP2.ID_CLIENTE,
CP2.TIPO, CP2.NOMBRE,DC.LUGAR, DC.OBSERVACION FROM
DETALLECIL DC left JOIN MOVCILINDROS MC ON DC.MOVCIL=MC.ID_MOV
INNER JOIN CILINDROS CI on DC.CIL=CI.ID_CILINDRO INNER JOIN
CLIEPROV CP1 ON MC.NOMDESTINO=CP1.ID_CLIENTE INNER JOIN
CLIEPROV CP2 ON CI.PROPIETARIO=CP2.ID_CLIENTE
INNER JOIN TIPOGASES TG ON CI.tipogasid=TG.id
WHERE CP1.id_cliente>0 and dc.id_detcil>0

Y ahora si parece estar todo ok con los indices. Pero la demora es la misma.

Caminante 17-05-2014 00:19:19

Ahora el nuevo plan es este:

Código SQL [-]
PLAN JOIN (JOIN (JOIN (DC INDEX (RDB$PRIMARY4), MC INDEX (RDB$PRIMARY6)), CI INDEX (RDB$PRIMARY1), CP1 INDEX (RDB$PRIMARY2)), CP2 INDEX (RDB$PRIMARY2), TG INDEX (PK_TIPOGASES))

duilioisola 17-05-2014 00:51:32

Prueba con la que te propuse, reordenando los joins y agregando left delante de cada uno:
Código SQL [-]
SELECT MC.ID_MOV, DC.ID_DETCIL, MC.FECHADOC, DC.CIL,CI.TIPOGASID, TG.TIPOGAS,
CI.DESCRIPCION,CI.CAPACIDAD, MC.SERIE, MC.DOCUMENTO,DC.PLAZO,
DC.FECHADEV, DC.DOCDEV,MC.NOMDESTINO, CP1.NOMBRE,CP2.ID_CLIENTE,
CP2.TIPO, CP2.NOMBRE,DC.LUGAR, DC.OBSERVACION
FROM
CLIEPROV CP1
LEFT JOIN MOVCILINDROS MC ON MC.NOMDESTINO=CP1.ID_CLIENTE
LEFT JOIN DETALLECIL DC ON DC.MOVCIL=MC.ID_MOV
LEFT JOIN CILINDROS CI ON DC.CIL=CI.ID_CILINDRO
LEFT JOIN CLIEPROV CP2 ON CI.PROPIETARIO=CP2.ID_CLIENTE
LEFT JOIN TIPOGASES TG ON CI.tipogasid=TG.id
WHERE
CP1.ID_CLIENTE > 0

Caminante 17-05-2014 01:39:38

Hola de nuevo

Cita:

Empezado por duilioisola (Mensaje 476550)
WHERE
CP1.ID_CLIENTE > 0
[/sql]

Bueno esta linea realmente no es necesaria. Solo la puse siguiendo un consejo de internet para obligar a utilizar un indice en el plan (Ya que daba natural join cp1 cuando no estaba esa linea).


Ya probe como me dijiste pero igual sigue con ese detalle en los mismos indices.


La franja horaria es GMT +2. Ahora son las 10:15:58.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi