MySQL改善性能执行时间

时间:2016-10-04 14:38:17

标签: mysql performance

我正在尝试提高以下查询的性能,以下执行查询花费93.2秒:

SELECT  year(date), month(date), `country_name_name`,
        CEIL(count(res.`user_xmpp_login`) /DAY(LAST_DAY(date))) as avgUser,
        CEIL(count(res.user)/DAY(LAST_DAY(date))) as avgPurchase
    FROM  
    (   SELECT  DATE(`user_registration_timestamp`) as date,
                user_country,
                NULL as user, `user_xmpp_login`
            FROM  users
            WHERE  `user_registration_timestamp` >= "2015-01-01 00:00:00"
              AND  `user_registration_timestamp`  < "2016-01-01 00:00:00"
            UNION  ALL 
        SELECT  DATE(`ts`) as date, user_country, user, NULL as `user_xmpp_login`
            FROM  purchase_log p
            INNER JOIN  users u  ON u.`user_xmpp_login` = p.`user`
            WHERE  `ts` >= "2015-01-01 00:00:00"
              AND  `ts`  < "2016-01-01 00:00:00"
              AND  result in ('ok', 'cancelled', 'pending') 
    ) AS res
    INNER JOIN  countries c  ON c.`country_id` = res.`user_country`
    INNER JOIN  country_names cn
               ON (cn.`country_name_country` = c.`country_id`
              AND  cn.`country_name_language` = 'en')
    GROUP BY  1,2,3
    ORDER BY  4 DESC,5 DESC, 3 ASC;

说明命令显示:    enter image description here 每个表的结构是:

购买表:

CREATE TABLE `purchase` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `result` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `iuser` (`user`),
) ENGINE=InnoDB AUTO_INCREMENT=12710221 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

用户表:

CREATE TABLE `users` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_country` int(11) DEFAULT NULL,
  `user_xmpp_login` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `user_registration_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `user_xmpp_login_UNIQUE` (`user_xmpp_login`),
  KEY `user_country_FK` (`user_country`),
  KEY `user_registration_timestamp` (`user_registration_timestamp`),
  CONSTRAINT `users_country_FK` FOREIGN KEY (`user_country`)
         REFERENCES `countries` (`country_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=33504745 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

国家/地区表

CREATE TABLE `countries` (
  `country_id` int(11) NOT NULL AUTO_INCREMENT,
  `country_code` varchar(2) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`country_id`),
) ENGINE=InnoDB AUTO_INCREMENT=508 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

国家/地区名称

CREATE TABLE `country_names` (
  `country_name_id` int(11) NOT NULL AUTO_INCREMENT,
  `country_name_country` int(11) NOT NULL,
  `country_name_language` char(2) COLLATE utf8_unicode_ci NOT NULL,
  `country_name_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`country_name_id`),
  UNIQUE KEY `country_name_country_language_UNIQUE`
            (`country_name_country`,`country_name_language`),
  KEY `country_name_language` (`country_name_language`),
  CONSTRAINT `country_name_country` FOREIGN KEY (`country_name_country`)
        REFERENCES `countries` (`country_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=45793 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

最大的问题似乎出现在您的用户表中。请记住,在大多数情况下,mysql每个表只能使用一个索引。在您的users表上,已使用user_xmpp_login_UNIQUE列将其加入purchase_log表。因此,user_registration_timestamp索引未用于涉及timestamp列的比较。

一个建议是在user_xmpp_loginuser_registration_timestamp列上创建综合索引。

答案 1 :(得分:1)

如果你为每个子查询计时,我认为你会发现users是最慢的组件。

purchase_log子查询可以用这个&#34;覆盖&#34; INDEX(result, ts, user)

将两个&#34;国家&#34;结合起来表! CHAR(2) CHARACTER SET ascii使用PRIMARY KEY,其他表使用JOINs。与INT不同,它只有2个字节,即4个字节和VARCHAR...,即3个字节(在本例中)。

你提到ts,但我不知道它来自哪里。如果它在purchase_log中,那么该表需要INDEX(user, ts)

2015年涉及users的百分比是多少?如果它超过20%,则INDEX(user_registration_timestamp)不会有帮助。

考虑:摆脱PRIMARY KEY(country_name_id),并将UNIQUE密钥提升为PRIMARY