php - mysql 5.7 在中等 sql 中比 mysql 5.6 慢很多

标签 php mysql sql-server query-cache

我们正在升级到 mysql 5.7,只是发现它比对应的 5.6 慢得多。虽然两者具有几乎相同的配置,但 5.6 版本在毫秒内执行大部分 sql,而另一个版本需要大约 1 秒或更长时间来执行中间复杂的 sql,例如下面的示例。

-- 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 行。我注意到我想“修复”两个有趣的行为:

  1. 删除 ORDER BY 使执行时间从 ~1.2 秒减少到 0.0015 秒!!
  2. mysql 5.7不缓存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 会出现这种奇怪的行为(还有很多其他 sql 在 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;

最佳答案

INNER JOIN <code>user</code> user_table_alias ON user_table_alias.<code>id</code> = <code>u</code>.<code>id</code>看起来没用。它仅针对自身进行连接,其余查询中不使用该技术。

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

此查询不能很好地适应表的大小,因为在界定“最近用户”是什么之前必须查看整个表。所以可能 myisam 使用的一些内部缓冲区现在溢出了。 这就是“使用临时”的意思。使用 filesort 意味着 order by 太大以至于使用临时文件,这对性能不利。

关于php - mysql 5.7 在中等 sql 中比 mysql 5.6 慢很多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38499811/

相关文章:

php - 如何将 MPTT 层次结构数据正确排序到多维数组中。

php - 检查 php session 字符串是否有效且存在

php - 与 vb.net 和 php 数据同步

MySQL查询不同列中上一行值和下一行值的差异

sql-server - 黑客可以欺骗或注入(inject)表单字段吗?

php - 尝试、捕获和重试

php - 注册页面上的操作 ="???"应该是什么?

mysql - Codeigniter 模型,根据 table1 从 2 个表中获取值。如果在 table2 上找不到值,则值返回 null

mysql : Algorithm to select most recent item per key in a history table

sql - 如何在sql函数中创建新表