我正在尝试提高以下查询的性能,以下执行查询花费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;
购买表:
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;
有什么建议吗?
答案 0 :(得分:1)
最大的问题似乎出现在您的用户表中。请记住,在大多数情况下,mysql每个表只能使用一个索引。在您的users表上,已使用user_xmpp_login_UNIQUE
列将其加入purchase_log表。因此,user_registration_timestamp索引未用于涉及timestamp列的比较。
一个建议是在user_xmpp_login
和user_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
。