2011-04-14 13 views
19

tengo 6 tablas:necesita ayuda para optimizar MySQL consulta

CREATE TABLE IF NOT EXISTS `sbpr_groups` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) DEFAULT NULL, 
    `active` tinyint(1) DEFAULT '0', 
    `dnd` tinyint(1) DEFAULT '0', 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=32 ; 

CREATE TABLE IF NOT EXISTS `sbpr_newsletter` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `from` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `mail` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `subject` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `body` text COLLATE utf8_unicode_ci, 
    `attach1` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `attach2` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `attach3` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=14; 

CREATE TABLE IF NOT EXISTS `sbpr_news_groups` (
    `newsletter_id` int(11) NOT NULL, 
    `groups` int(11) NOT NULL, 
    KEY `fk_sbpr_news_groups_sbpr_newsletter1` (`newsletter_id`), 
    KEY `fk_sbpr_news_groups_sbpr_groups1` (`groups`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

CREATE TABLE IF NOT EXISTS `sbpr_news_recs` (
    `newsletter_id` int(11) NOT NULL, 
    `recipients` int(11) NOT NULL, 
    KEY `fk_sbpr_news_recs_sbpr_newsletter1` (`newsletter_id`), 
    KEY `fk_sbpr_news_recs_sbpr_recipients1` (`recipients`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

CREATE TABLE IF NOT EXISTS `sbpr_recipients` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `mail` varchar(160) DEFAULT NULL, 
    `date_reg` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `active` tinyint(1) DEFAULT '0', 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3008 ; 

CREATE TABLE IF NOT EXISTS `sbpr_rec_groups` (
    `rec_id` int(11) NOT NULL, 
    `group` int(11) NOT NULL, 
    KEY `fk_sbpr_rec_groups_sbpr_recipients` (`rec_id`), 
    KEY `fk_sbpr_rec_groups_sbpr_groups1` (`group`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 

Con estas claves foregin:

ALTER TABLE `sbpr_news_groups` 
    ADD CONSTRAINT `fk_sbpr_news_groups_sbpr_groups1` 
    FOREIGN KEY (`groups`) REFERENCES `sbpr_groups` (`id`) 
    ON DELETE CASCADE ON UPDATE NO ACTION, 
    ADD CONSTRAINT `fk_sbpr_news_groups_sbpr_newsletter1` 
    FOREIGN KEY (`newsletter_id`) REFERENCES `sbpr_newsletter` (`id`) 
    ON DELETE CASCADE ON UPDATE NO ACTION; 

ALTER TABLE `sbpr_news_recs` 
    ADD CONSTRAINT `fk_sbpr_news_recs_sbpr_newsletter1` 
    FOREIGN KEY (`newsletter_id`) REFERENCES `sbpr_newsletter` (`id`) 
    ON DELETE CASCADE ON UPDATE NO ACTION, 
    ADD CONSTRAINT `fk_sbpr_news_recs_sbpr_recipients1` 
    FOREIGN KEY (`recipients`) REFERENCES `sbpr_recipients` (`id`) 
    ON DELETE CASCADE ON UPDATE NO ACTION; 

ALTER TABLE `sbpr_rec_groups` 
    ADD CONSTRAINT `fk_sbpr_rec_groups_sbpr_groups1` 
    FOREIGN KEY (`group`) REFERENCES `sbpr_groups` (`id`) 
    ON DELETE CASCADE ON UPDATE NO ACTION, 
    ADD CONSTRAINT `fk_sbpr_rec_groups_sbpr_recipients` 
    FOREIGN KEY (`rec_id`) REFERENCES `sbpr_recipients` (`id`) 
    ON DELETE CASCADE ON UPDATE NO ACTION; 

estructura visual de tablas: enter image description here

Quiero seleccionar todos los r OWS de sbpr_newsletter mesa, y añadir a cada una de estas líneas el número de filas de sbpr_recipients cuya ID prescrita en sbpr_news_recs o prescritas en sbpr_rec_groups depence en FKs.

Ej. Quiero seleccionar el recuento de todos los destinatarios del boletín informativo que están en sbpr_news_recs o existe en el grupo que están en sbpr_rec_groups más el recuento de destinatarios activos. SQL

He workinq:

SELECT d.id, d.subject , d.created_date, 
    (SELECT count(*) FROM sbpr_recipients r 
     LEFT JOIN sbpr_news_recs nr ON nr.recipients = r.id 
     LEFT JOIN sbpr_rec_groups g ON g.rec_id = r.id 
     LEFT JOIN sbpr_news_groups ng ON ng.groups = g.group 
     WHERE nr.newsletter_id = d.id OR ng.newsletter_id = d.id) AS repicients, 

    (SELECT count(*) FROM sbpr_recipients r 
     LEFT JOIN sbpr_news_recs nr ON nr.recipients = r.id 
     LEFT JOIN sbpr_rec_groups g ON g.rec_id = r.id 
     LEFT JOIN sbpr_news_groups ng ON ng.groups = g.group 
     WHERE (nr.newsletter_id = d.id OR ng.newsletter_id = d.id) 
     AND r.active = 1) AS active_repicients 
FROM sbpr_newsletter d 
ORDER BY d.id ASC, d.id 

Explicar de este SQL: enter image description here

Pregunta: ¿Cómo puedo optimizar mi sql?

+9

+1 para todos los detalles. Ojalá hubiera más preguntas como esta. – Wes

+0

¿Cómo se ve su explicación cuando cambia 'orden por d.id ASC, d.id' por' ordena por d.id ASC'? – eisberg

+0

@eisberg http://imm.io/4YVk –

Respuesta

12

Sólo acercarse a optimizar, dos consultas SELECT se transfieren en la cláusula JOIN -

SELECT d.id 
    , d.subject 
    , d.created_date 
    , count(if(nr_newsletter_id is not null or ng_newsletter_id is not null, 1, null)) repicients 
    , count(if((nr_newsletter_id is not null or ng_newsletter_id is not null) and t.active = 1, 1, null)) active_repicients 
FROM 
    sbpr_newsletter d 
LEFT JOIN (
    SELECT nr.newsletter_id nr_newsletter_id 
     , ng.newsletter_id ng_newsletter_id 
     , r.active 
    FROM 
    sbpr_recipients r 
    LEFT JOIN sbpr_news_recs nr 
    ON nr.recipients = r.id 
    LEFT JOIN sbpr_rec_groups g 
    ON g.rec_id = r.id 
    LEFT JOIN sbpr_news_groups ng 
    ON ng.groups = g.group 
) t 
ON nr_newsletter_id = d.id OR ng_newsletter_id = d.id 
GROUP BY 
    d.id; 

I reescrito su consulta un poco, no es probado, pero lo intentan.

+0

¡Muy bonito! Se ejecuta dos veces más rápido que mi variante. –

+1

+1 para el SELECCIONAR dentro de una UNIÓN IZQUIERDA muy agradable. – Johan

+0

Acabo de notar los resultados de su consulta y mi es diferente: http://imm.io/4YWf –

0

Se puede crear una vista y consulta que en lugar - el comercio fuera es el almacenamiento, pero debería eliminar enormemente la carga del servidor ...

0

La subconsulta para los receptores/active_recipients ejecuta dos veces, y cada vez que devuelve registros de 3311, por lo que valdría la pena definir como una vista.

De lo contrario, defina los índices en las claves externas que utiliza en las uniones.

+0

La consulta de @Devart se ejecuta al mismo tiempo con índices y sin ellos, ¿aún necesito agregar índices? –

Cuestiones relacionadas