I want to get some emails in a database and each email have a status. All the possible status are stock in a table where they all have permissions (such as show, edit, delete, etc.). Those emails are not users with permissions trough a site but a list of emails a user have added.
Here is the tables structure:
Email table
CREATE TABLE IF NOT EXISTS `email__email` ( `email_id` int(11) NOT NULL AUTO_INCREMENT, `created` timestamp NULL DEFAULT NULL, `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `user_fk` int(11) NOT NULL, `status_fk` tinyint(2) NOT NULL, `language` enum('fr','en') COLLATE utf8_unicode_ci DEFAULT NULL, `email` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `firstName` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `lastName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, `companyName` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `gender` enum('f','m') COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`email_id`), UNIQUE KEY `user_email` (`user_fk`,`email`), KEY `user_fk` (`user_fk`), KEY `created` (`created`), KEY `status_fk` (`status_fk`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3031492 ;
Status table
CREATE TABLE IF NOT EXISTS `email__status` ( `status_id` int(11) NOT NULL AUTO_INCREMENT, `name_fr` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL, `name_en` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL, `description_fr` varchar(150) COLLATE utf8_unicode_ci DEFAULT NULL, `description_en` varchar(150) COLLATE utf8_unicode_ci DEFAULT NULL, `permShow` tinyint(1) NOT NULL DEFAULT '0', `permSend` tinyint(1) NOT NULL DEFAULT '0', `permEdit` tinyint(1) NOT NULL DEFAULT '0', `permDelete` tinyint(1) NOT NULL DEFAULT '0', `permImport` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`status_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=7 ;
Here is the slow query with the EXPLAIN:
SELECT EE.*, ES.name_fr AS statusName, ES.description_fr AS statusDescription, ES.permShow, ES.permSend, ES.permEdit, ES.permDelete, ES.permImport , (SELECT GROUP_CONCAT(CONVERT(CONCAT(GC.name, '~', GC.group_id), CHAR(255)) SEPARATOR ',') FROM `group` GC INNER JOIN group_email GEC ON GEC.group_fk = GC.group_id WHERE GEC.email_fk = EE.email_id AND GC.deleted = 0) AS groups FROM `email__email` EE INNER JOIN email__status ES ON EE.status_fk = ES.status_id WHERE 1 = 1 AND EE.user_fk = 54 AND ES.permShow = 1 ORDER BY EE.email_id DESC LIMIT 15 EXTRA ID KEY KEY_LEN POSSIBLE_KEYS REF ROWS SELECT_TYPE TABLE TYPE Using temporary; Using filesort 1 user_email 4 user_email,user_fk,status_fk const 180681 PRIMARY EE ref Using where; Using join buffer 1 [empty string] [empty string] PRIMARY [empty string] 6 PRIMARY ES ALL Using index 2 email_fk 4 group_email,group_fk,email_fk mailing_dev.EE.email_id 1 DEPENDENT SUBQUERY GEC ref Using where 2 PRIMARY 4 PRIMARY mailing_dev.GEC.group_fk 1 DEPENDENT SUBQUERY GC eq_ref
Here is a fast query with the EXPLAIN:
SELECT EE.* , (SELECT GROUP_CONCAT(CONVERT(CONCAT(GC.name, '~', GC.group_id), CHAR(255)) SEPARATOR ',') FROM `group` GC INNER JOIN group_email GEC ON GEC.group_fk = GC.group_id WHERE GEC.email_fk = EE.email_id AND GC.deleted = 0) AS groups FROM `email__email` EE WHERE 1 = 1 AND EE.user_fk = 54 AND EXISTS(SELECT permShow FROM email__status WHERE status_id = EE.status_fk AND permShow = 1) ORDER BY EE.email_id DESC LIMIT 15 EXTRA ID KEY KEY_LEN POSSIBLE_KEYS REF ROWS SELECT_TYPE TABLE TYPE Using where 1 PRIMARY 4 user_email,user_fk [empty string] 270 PRIMARY EE index Using where 3 PRIMARY 4 PRIMARY mailing_dev.EE.status_fk 1 DEPENDENT SUBQUERY email__status eq_ref Using index 2 email_fk 4 group_email,group_fk,email_fk mailing_dev.EE.email_id 1 DEPENDENT SUBQUERY GEC ref Using where 2 PRIMARY 4 PRIMARY mailing_dev.GEC.group_fk 1 DEPENDENT SUBQUERY GC eq_ref
There is a big difference between both queries but the second one doesn't give me two important columns that I need to fetch. I can do subqueries to fetch them like a join would do but still, I don't want to have a lot of subqueries for each... any ideas to improve this ?
Thanks
email__email.status_fk
is a tinyint, but email__status.status_id
is an int(11).
This probably is fouling up your INNER JOIN. Change one or the other data type and try again.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.