MyISAM -> InnoDB 并迁移到 AWS 后 mysql 查询变慢

标签 mysql innodb amazon-rds myisam

我计划从共享托管服务器切换到 AWS 设置(适用于 apache/php 的 EC2、适用于 MySQL 的 RDS)。

我的 php/mysql 网站的测试版在共享服务器上运行了一年多。特别是一个页面在浏览器中总是运行得很快(可能 < 3 秒即可完全加载)。

在准备迁移时,我将数据库和所有表从 MyISAM 更改为 InnoDB。我还将默认字符集切换为 utf8mb4(是 latin-1 或其他)并将排序规则切换为 utf8mb4_unicode_ci。有几个类似 varchar2(400) 的列被索引,出现 > 191 个字符错误(因为使用 utf8mb4 从 3byte->4byte 移动)。我进去并手动将这些列切换为 UTF-8/utf_unicode_ci。一切看起来都很好(没有明显的错误)

现在,我已将站点/数据库的副本移至 AWS。大多数页面加载良好。尤其是这个加载时间很长(> 5 分钟)。我有一些非常小的 EC2 实例和 RDS 实例,因此我意识到这可能是一个问题,但我是唯一使用该站点(用于一个查询)的人,并且整个数据库小于 70MB。

运行解释计划显示在大多数情况下使用键(索引?)以及一个具有 74k 行的“派生”表。 74k 是一个非常小的数据集。我对 Oracle 解释计划更加熟悉,因此我很难弄清楚发生了什么。

我尝试在共享托管服务器上运行原始页面,它也变得慢得多!因此,我没有理由相信这是 AWS 问题。

我知道MyISAM在简单场景下要快一点,但是它不可能比我新使用的InnoDB快10000000000000倍吧?

尝试对超过 191 个字符的 varchar 进行索引时,转换是否出现问题?有没有可能它只是以某种方式破坏了系统/表格?如果您给它们大量的时间,查询就会完成,但它们不可能这么慢。我认为即使索引被炸掉并且它对 74k 行进行全表扫描,它也不应该费力。

想法?

编辑: 找到了这个线程: https://dba.stackexchange.com/questions/75091/why-are-simple-selects-on-innodb-100x-slower-than-on-myisam 发帖人似乎也有类似的减速经历。我不能使用与他/她相同的解决方案。认为我必须将所有想要返回的列放入索引中是疯狂的。这不可能是大家都能接受的吧?

最佳答案

好吧,我明白了。是我的错(不足为奇)。我很久以前就写了这个查询,当时我才真正知道自己在做什么。绝对还有改进的空间......

查询看起来像这样:

TableA (main table of focus)
  aID (pk)
  bID (fk)
  locationID (fk)
  rowTitle

TableB 
  bID (pk)
  locationID (fk)

TableLocations
  locationID (pk)
  locationName

我想基本上使用 A 的位置(如果存在),但如果 A 没有,则回退到 B 的位置。 (A 总是链接到 B)。

我正在做一些类似的事情

 SELECT
   rowTitle,
   locationName
 FROM
   TableA a, TableB b, TableLocations loc
 WHERE
  a.bID = b.bID
  AND
  ( a.locationID = loc.locationID
    OR 
   (a.locationID IS NULL AND b.locationID = loc.locationID)
  )

它运行良好,并且在使用 MyISAM 时总是返回我想要的内容。而且速度非常快。然而,当我由于某种原因转移到 InnoDB 时,sh$& 遇到了困难。不知道引擎在执行此查询的计划时有何不同。我想在某个时刻,当数据集足够大时,MyISAM 会被阻塞,但由于我仍处于 dev/uat 状态,数据很小。

此后我转向了结构更好的东西,例如:

 SELECT 
   rowTitle
   CASE WHEN loc1.locationID IS NOT NULL THEN loc1.locationName
        WHEN loc2.locationID IS NOT NULL THEN loc2.locationName
   END as locationName
FROM
   TableA a
JOIN TableB b ON a.bID = b.bID
 LEFT OUTER JOIN TableLocations loc1 ON a.locationID = loc1.locationID
 LEFT OUTER JOIN TableLocations loc2 ON b.locationID = loc2.locationID

一切都很好!我删除了很多查询和其他表,以专注于我的主要逻辑/物理问题。

查询时间减少到大约 10MS,这正是我所期望的。

这是我对 MySQL 又爱又恨的一件事。有时“它确实有效”,让你审视自己的不足。绝对是我的错,因为第一次没有做对......

附加问题: 如果有人知道 MyISAM 与 InnoDB 如何评估第一个(糟糕的)查询之间的差异以及为什么性能如此不同,我真的很想听听!

谢谢!

关于MyISAM -> InnoDB 并迁移到 AWS 后 mysql 查询变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41887382/

相关文章:

php - 获取先前的数组值

mysql - 有什么方法可以使用 mysqlimport 选项卡选项禁用外键检查?

php - 如何使用列名作为值并过滤最高值MYSQL/PHP

mysql - 了解 mysql 字符集和排序规则

ruby - 带有 Amazon RDS 的 VPC 中的 AWS Elastic Beanstalk

mysql - 当我使用数字类型选择 varchar 列时会发生什么?

mysql - VARCHAR 或 INT 列的性能变化有多大 - MySQL

mysql - 表锁如何影响表引擎从 MyISAM 到 InnoDB 的变化?

amazon-rds - 断开连接后,RDS 代理成功连接,显示 "RDS Proxy supports only IAM or MD5 authentication"

mysql - AWS RDS : Load XML From S3?