[英]mysql 5.7 is much slower than mysql 5.6 in medium sql
我們正在升級到mysql 5.7,只是發現它比5.6計數器要慢得多。 雖然兩者的配置幾乎相同,但5.6版本以毫秒為單位執行大多數sql,而對於中等復雜的sql(例如下面的sql),另一個版本大約需要1秒鍾或更長時間。
-- Getting most recent users that are email-verified and not banned
SELECT
`u`.*
FROM
`user` AS `u`
INNER JOIN `user` user_table_alias ON user_table_alias.`id` = `u`.`id`
LEFT JOIN `user_suspend` user_suspend_table_alias ON user_suspend_table_alias.`userId` = `user_table_alias`.`id`
WHERE
(
`user_suspend_table_alias`.`id` IS NULL
)
AND
`user_table_alias`.`emailVerify` = 1
ORDER BY
`u`.`joinStamp` DESC
LIMIT 1, 18
這兩個表都非常簡單並且索引良好:
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(128) NOT NULL DEFAULT '',
`username` varchar(32) NOT NULL DEFAULT '',
`password` varchar(64) NOT NULL DEFAULT '',
`joinStamp` int(11) NOT NULL DEFAULT '0',
`activityStamp` int(11) NOT NULL DEFAULT '0',
`accountType` varchar(32) NOT NULL DEFAULT '',
`emailVerify` tinyint(2) NOT NULL DEFAULT '0',
`joinIp` int(11) unsigned NOT NULL,
`locationId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
UNIQUE KEY `username` (`username`),
KEY `accountType` (`accountType`),
KEY `joinStamp` (`joinStamp`),
KEY `activityStamp` (`activityStamp`)
) ENGINE=MyISAM AUTO_INCREMENT=89747 DEFAULT CHARSET=utf8 COMMENT='utf8_general_ci';
-- ----------------------------
-- Table structure for user_suspend
-- ----------------------------
DROP TABLE IF EXISTS `user_suspend`;
CREATE TABLE `user_suspend` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userId` int(11) DEFAULT NULL,
`timestamp` int(11) DEFAULT NULL,
`message` text NOT NULL,
`expire` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `userId` (`userId`)
) ENGINE=MyISAM AUTO_INCREMENT=513 DEFAULT CHARSET=utf8;
這些表分別具有約100K和1K行。 我注意到了兩個我想“修復”的有趣行為:
注意:我們有緩存查詢:
顯示狀態,例如“ Qcache%”
Qcache_free_blocks 19408
Qcache_free_memory 61782816
Qcache_hits 31437169
Qcache_inserts 2406719
Qcache_lowmem_prunes 133483
Qcache_not_cached 43555
Qcache_queries_in_cache 41691
Qcache_total_blocks 103951
我用谷歌搜索發現了關於5.7的許多問題,但是卻不明白為什么這個sql出現這種奇怪的行為(仍然有很多其他的sql在5.7上運行得慢得多)。
這是Neville K建議的解釋:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE user_table_alias NULL ALL PRIMARY NULL NULL NULL 104801 10.00 Using where; Usingtemporary; Usingfilesort
1 SIMPLE u NULL eq_ref PRIMARY PRIMARY 4 knn.base_user_table_alias.id 1 100.00 NULL
1 SIMPLE user_suspend_table_alias NULL ref userId userId 5 knn.base_user_table_alias.id 1 10.00 Using where;
INNER JOIN
user
user_table_alias ON user_table_alias. id
= u
. id
INNER JOIN
user
user_table_alias ON user_table_alias. id
= u
. id
看起來沒用。 它僅與自身連接,在其余的查詢中未使用該技術。 INNER JOIN
user
user_table_alias ON user_table_alias. id
= u
. id
emailVerify
上沒有索引。 由EXPLAIN的第一行指示。 (“在哪里使用”表示不使用索引)
此查詢不能很好地擴展表的大小,因為在界定“最近的用戶”之前,必須先查看整個表。 因此,myisam使用的某些內部緩沖區現在可能已溢出。 這就是“使用臨時”的意思。 使用文件排序意味着順序很大,因此使用了臨時文件,這對性能不利。
好的,感謝NevilleK在Explain上的發言。
我想出了如何僅修復此SQL:
user_table_alias.emailVerify = 1
至
u.emailVerify = 1
我不知道為什么,但是在MySQL5.6中,兩者都以毫秒為單位執行。
我想我得回顧所有SQL(來自其他開發者),這要歸功於MySQL的向后改進
自連接看起來很多余。
我認為您可以按以下方式重新編寫查詢:
SELECT
`u`.*
FROM
`user` AS `u`
LEFT JOIN `user_suspend` user_suspend_table_alias ON user_suspend_table_alias.`userId` = `u`.`id`
WHERE `user_suspend_table_alias`.`id` IS NULL
AND `u`.`emailVerify` = 1
ORDER BY
`u`.`joinStamp` DESC
LIMIT 1, 18
我假設“ emailVerify”是僅包含少量值(0和1)的列,因此不應該對其進行索引。 我還假定“ joinStamp”是某種時間戳(盡管數據類型是整數)。 如果是這樣,您可以創建一個索引來進一步加快速度。
create index id_joinstamp on user (id, joinstamp)
作為解決方法,您可以在首次選擇后嘗試使用關鍵字STRAIGHT_JOIN。 此關鍵字強制mysql從左到右連接( MYSQL-STRAIGHT_JOIN在此代碼中做什么? )。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.