[英]MySQL query optimization - increase speed and efficiency
我想在數據庫中獲取一些電子郵件,每個電子郵件都有一個狀態。 所有可能的狀態都存儲在一個表中,它們都在其中具有權限(例如顯示,編輯,刪除等)。 這些電子郵件不是具有網站權限的用戶,而是用戶已添加的電子郵件列表。
這是表格結構:
電子郵件表格
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 ;
狀態表
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 ;
這是使用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
這是使用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
這兩個查詢之間有很大的區別,但是第二個查詢沒有給我提供我需要獲取的兩個重要列。 我可以執行子查詢以像聯接一樣獲取它們,但仍然,我不想為每個子查詢提供很多子查詢...有什么想法可以改善這一點?
謝謝
email__email.status_fk
是tinyint,但是email__status.status_id
是int(11)。
這可能會破壞您的INNER JOIN。 更改一種或另一種數據類型,然后重試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.