I have 6 tables:
我有6张桌子:
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;
With this foregin keys:
使用此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;
Visual structure of tables:
表的可视结构:
I want to select all rows from sbpr_newsletter table, and add to each of these lines the number of rows from sbpr_recipients whose id prescribed in sbpr_news_recs or prescribed in sbpr_rec_groups depence on FKs.
我想从sbpr_newsletter表中选择所有行,并在每个行中添加sbpr_recipients中的行数,这些行的sbpr_news_recs中规定的id或sbpr_rec_groups中规定的fK依赖于fKs。
Ex. I whant to select count of all recipients of curent newsletter wich are in sbpr_news_recs or exists in group wich are in sbpr_rec_groups plus count of active recipients.
防爆。我想选择在sbpr_news_recs中存在的所有收件人的数量,或者存在于sbpr_rec_groups中的组中,加上活跃收件人的数量。
I have workinq SQL:
我有workinq SQL:
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
Explain of this sql:
解释这个sql:
Question: How can I optimize my sql?
问题:如何优化我的sql?
3 个解决方案
#1
12
Just approach to optimize, two SELECT queries are transfered into JOIN clause -
只是进行优化,将两个SELECT查询转换为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 rewrited your query a little, it is not tested, but try it.
我重新写了一下你的查询,它没有经过测试,但是试试看。
#2
0
You COULD create a view and query that instead - trade off is storage but should vastly remove load from server...
你可以创建一个视图和查询,相反 - 权衡是存储,但应该大大删除服务器的负载......
#3
0
The subquery for recipients / active_recipients runs twice, and each time returns 3311 records, so it would be worth defining as a view.
recipients / active_recipients的子查询运行两次,每次返回3311条记录,因此值得定义为视图。
Otherwise, define indexes on the foreign keys you use in joins.
否则,在连接中使用的外键上定义索引。
#1
12
Just approach to optimize, two SELECT queries are transfered into JOIN clause -
只是进行优化,将两个SELECT查询转换为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 rewrited your query a little, it is not tested, but try it.
我重新写了一下你的查询,它没有经过测试,但是试试看。
#2
0
You COULD create a view and query that instead - trade off is storage but should vastly remove load from server...
你可以创建一个视图和查询,相反 - 权衡是存储,但应该大大删除服务器的负载......
#3
0
The subquery for recipients / active_recipients runs twice, and each time returns 3311 records, so it would be worth defining as a view.
recipients / active_recipients的子查询运行两次,每次返回3311条记录,因此值得定义为视图。
Otherwise, define indexes on the foreign keys you use in joins.
否则,在连接中使用的外键上定义索引。