MySQL - GROUP BY减慢页面速度

时间:2015-04-05 05:32:59

标签: php mysql

下面的查询中的GROUP BY子句使页面变慢,请帮助解决此问题

 SELECT 
    `a`.*, 
    CONCAT(a.`firstname`, " ", a.`lastname`) AS `cont_name`,
    CONCAT(a.`position`, " / ", a.`company`) AS `comp_pos`,
    CONCAT(f.`firstname`, " ", f.`lastname`) AS `created_by` 
FROM 
    `contacts` AS `a`
    LEFT JOIN `users` AS `f` ON f.id = a.user_id
    LEFT JOIN `user_centres` AS `b` ON a.user_id = b.user_id
WHERE b.centre_id IN (23, 24, 25, 26, 20, 21, 22, 27, 28)
GROUP BY `a`.`id` 
ORDER BY `a`.`created` desc

此处与user_centres表的连接用于中心过滤数据。 EXPLAIN将结果显示为:

- 1 SIMPLE a index PRIMARY,user_id,area_id,industry_id,country PRIMARY 4 NULL 20145 Using temporary; Using filesort

我们的要求如下

  1. 在admin login中列出所有联系人

  2. 经理/职员登录中的联系人中心明智列表

  3. 联系表中的总记录是> 20K。

    user_centres表中的用户将有多个条目,即:用户被分配到多个中心。

    通过排除GROUP BY在服务器中执行查询是近300k数据,这就产生了问题。

    Db结构

    contacts的表结构

    CREATE TABLE IF NOT EXISTS `contacts` (
    `id` int(11) NOT NULL,
    `user_id` int(11) DEFAULT NULL,
    `imported` tinyint(4) NOT NULL DEFAULT '0',
    `situation` char(10) DEFAULT NULL,
    `firstname` varchar(150) DEFAULT NULL,
    `lastname` varchar(150) DEFAULT NULL,
    `position` varchar(150) DEFAULT NULL,
    `dob` datetime DEFAULT NULL,
    `office_contact` varchar(100) DEFAULT NULL,
    `mobile_contact` varchar(100) DEFAULT NULL,
    `email` varchar(255) NOT NULL,
    `company` varchar(150) DEFAULT NULL,
    `industry_id` int(11) DEFAULT NULL,
    `address` varchar(255) DEFAULT NULL,
    `city` varchar(150) DEFAULT NULL,
    `country` int(11) DEFAULT NULL,
    `isclient` tinyint(4) NOT NULL DEFAULT '0',
    `classification` varchar(100) DEFAULT NULL,
    `created` datetime NOT NULL,
    `updated` datetime NOT NULL,
    `unsubscribe` enum('Y','N') NOT NULL DEFAULT 'N'
    ) ENGINE=InnoDB AUTO_INCREMENT=25203 DEFAULT CHARSET=latin1;
    

    表格contacts

    的索引
    ALTER TABLE `contacts`
     ADD PRIMARY KEY (`id`), ADD KEY `user_id` (`user_id`),
    ADD KEY `industry_id` (`industry_id`), ADD KEY `country` (`country`);
    

    contacts

    的约束
    ALTER TABLE `contacts`
    ADD CONSTRAINT `contacts_ibfk_4` FOREIGN KEY (`user_id`) 
    REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION,
    ADD CONSTRAINT `contacts_ibfk_6` FOREIGN KEY (`industry_id`) 
    REFERENCES `industries` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION,
    ADD CONSTRAINT `contacts_ibfk_7` FOREIGN KEY (`country`) 
    REFERENCES `country` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
    

    users的表结构

    CREATE TABLE IF NOT EXISTS `users` (
    `id` int(11) NOT NULL,
    `role_id` int(11) NOT NULL,
    `email` varchar(250) NOT NULL,
    `password` varchar(45) NOT NULL,
    `salt` varchar(45) DEFAULT NULL,
    `status_id` int(11) DEFAULT NULL,
    `status` tinyint(1) DEFAULT '1',
    `firstname` varchar(255) NOT NULL,
    `lastname` varchar(255) NOT NULL,
    `created` datetime DEFAULT NULL,
    `updated` datetime DEFAULT NULL
    ) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=latin1;
    

    表格users

    的索引
    ALTER TABLE `users`
    ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `email_UNIQUE` (`email`),
    ADD KEY `type_id_idx` (`role_id`), ADD KEY `status_id_idx` (`status_id`);
    

    users

    的约束
    ALTER TABLE `users`
    ADD CONSTRAINT `role_id` FOREIGN KEY (`role_id`) 
    REFERENCES `users_roles` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
    ADD CONSTRAINT `status_id` FOREIGN KEY (`status_id`) 
    REFERENCES `users_status` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
    ADD CONSTRAINT `users_ibfk_1` FOREIGN KEY (`area`) 
    REFERENCES `area` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
    

    user_centres的表结构

    CREATE TABLE IF NOT EXISTS `user_centres` (
    `id` int(11) NOT NULL,
    `user_id` int(11) NOT NULL,
    `area_id` int(11) NOT NULL,
    `centre_id` int(11) NOT NULL
    ) ENGINE=InnoDB AUTO_INCREMENT=72 DEFAULT CHARSET=utf8;
    

    表格user_centres

    的索引
    ALTER TABLE `user_centres`
    ADD PRIMARY KEY (`id`), ADD KEY `user_id` (`user_id`),
    ADD KEY `centre_id` (`centre_id`), ADD KEY `area_id` (`area_id`);
    

    user_centres

    的约束
    ALTER TABLE `user_centres`
    ADD CONSTRAINT `user_centres_ibfk_1` FOREIGN KEY (`user_id`) 
    REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
    ADD CONSTRAINT `user_centres_ibfk_2` FOREIGN KEY (`centre_id`) 
    REFERENCES `centre` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION;
    

    另请参阅EXPLAIN屏幕 - http://prntscr.com/6o5h8s

3 个答案:

答案 0 :(得分:0)

由于ORDER BY GROUP BY子句的不同,

未使用索引。

http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html

答案 1 :(得分:0)

你花了很多时间检查user_centres,但不需要任何东西。从查询中删除它。

users可以成为相关子查询:

SELECT  `a`.*,
        CONCAT(a.`firstname`, " ", a.`lastname`) AS `cont_name`,
        CONCAT(a.`position`, " / ", a.`company`) AS `comp_pos`,
        ( SELECT  CONCAT(f.`firstname`, " ", f.`lastname`)
            FROM  `users` AS `f` ON f.id = a.user_id 
        ) AS `created_by`
    FROM  `contacts` AS `a`
    GROUP BY  `a`.`id`
    ORDER BY  `a`.`created` desc 

你真的需要所有20K行吗?结果的绝大部分是缓慢的一部分。

答案 2 :(得分:0)

谢谢大家,基于你们所有人的反馈,我现在尝试了下面的查询,并将速度从30秒提高到15秒

SELECT  `a`.`id`, `a`.`user_id`, `a`.`imported`, `a`.`created`,
        `a`.`unsubscribe`, CONCAT(a.firstname, " ", a.lastname) AS `cont_name`,
        CONCAT(a.position, " / ", a.company) AS `comp_pos`, 
      ( SELECT  COUNT(uc.id)
            FROM  `user_centres` AS `uc`
            WHERE  (uc.user_id = a.user_id)
              AND  (uc.centre_id IN (29))
            GROUP BY  `uc`.`user_id`
      ) AS `centre_cnt`, 
      ( SELECT  GROUP_CONCAT(DISTINCT g.group_name
                    ORDER BY  g.group_name ASC SEPARATOR ", ")
            FROM  `groups` AS `g`
            INNER JOIN  `group_contacts` AS `gc` ON g.id = gc.group_id
            WHERE  (gc.contact_id = a.id)
            GROUP BY  `gc`.`contact_id`
      ) AS `group_name`, 
      ( SELECT  CONCAT(u.`firstname`, " ", u.`lastname`)
            FROM  `users` AS `u`
            WHERE  (u.id = a.user_id)
      ) AS `created_by`, `e`.`name` AS `industry_name`
    FROM  `contacts` AS `a`
    LEFT JOIN  `industries` AS `e` ON e.id = a.industry_id
    WHERE  (1)
    HAVING  (centre_cnt is NOT NULL)
    ORDER BY  `a`.`id` desc

让我知道有没有办法提高速度并使页面加载低于5秒。

请参阅界面(注意过滤和排序字段) - http://prntscr.com/6q6q70