在中型sql中,mysql 5.7比mysql 5.6慢得多

时间:2016-07-21 09:09:29

标签: php mysql sql-server query-cache

我们正在升级到mysql 5.7并且发现它比它的5.6计数器部分慢得多。虽然两者的配置几乎完全相同,但5.6版本以毫秒为单位执行大部分sqls,而另一个版本对于中间复杂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行。我注意到了两个有趣的行为,我想和#34;修复" :

  1. 删除ORDER BY将执行时间从~1.2秒带到0.0015秒!!
  2. mysql 5.7
  3. 不缓存sql

    注意:我们有缓存查询:

    显示状态' 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上(还有很多其他的sqls在5.7上运行得慢得多)。

    以下是Neville K建议的EXPLAIN:

    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;
    

4 个答案:

答案 0 :(得分:2)

INNER JOIN user user_table_alias ON user_table_alias.id = u.id看起来毫无用处。它只与自身连接,并且在查询的其余部分中不使用该技术。

user上没有索引。这由EXPLAIN的第一行表示。 ('使用where'表示不使用索引)

此查询不能很好地扩展表的大小,因为在分隔最近用户'之前必须查看完整表。是。因此,myisam使用的内部缓冲区现在可能已溢出。 这就是'使用临时'手段。使用filesort意味着order by太大,它使用的是临时文件,这对性能有害。

答案 1 :(得分:1)

好的,感谢NevilleK on Explain。

我想出了如何只修复这个SQL:

 user_table_alias.emailVerify = 1 

u.emailVerify = 1

我不知道为什么,但在MySQL5.6中,两者都是以毫秒为单位执行的。

我想我将不得不审查所有SQL(来自其他开发人员),这要归功于MySQL的落后改进

答案 2 :(得分:1)

自我加入看起来多余。

我认为您可以按如下方式重新编写查询:

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)

答案 3 :(得分:0)

作为一种解决方法,您可以在首次选择后尝试使用关键字STRAIGHT_JOIN。此关键字强制mysql从左到右连接(MYSQL - What does STRAIGHT_JOIN do in this code?)。

相关问题