【问题标题】:MySQL does not utilize server fullyMySQL 没有充分利用服务器
【发布时间】:2016-02-26 10:59:27
【问题描述】:

我在 Amazon RDS db.m4.xlarge(16Gb RAM,4vCPU)多可用区部署上运行 MariaDB 10.0.17。我们使用最大设置为 10000 IOPS 的预置 IOPS 存储。 users 表包含 17M 条记录; user_properties 表包含 350M 条记录。

user_properties 表描述了附加到用户的道具的“地图”。 upkey 是键,string_valueinteger_value 等是每种类型的值;字符串、日期、整数、双精度。索引也是每种类型的。

我们尝试向user_properties 表插入更多数据:应用程序将数据插入INNODB 临时表TEMP1,然后将数据从TEMP1 复制到user_properties 表。

问题是我们只能达到 2500 写入 IOPS 和 500-1000 读取 IOPS。队列深度平均保持在 7 左右。 MySQL 服务器 CPU 使用率保持在 20-30%,从未达到 60%。 应用程序似乎向 MySQL 提供了足够的数据:我们将类似的数据文件提供给 DB,并查看处理时间如何随着表大小的增加而增加。 大多数时间应用程序等待 MySQL 查询完成。在这个过程中,插入TEMP1 表只需要一小部分时间,大部分时间是等待从TEMP1 表插入到user_properties

有人可以帮我加快 MySQL 的速度吗?我应该增加/改变什么?

CREATE TABLE IF NOT EXISTS `users` (
  `id` bigint(20), // Column is not used now. Filled with NULL
  `version` bigint(20) NOT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `uuid` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL,
  `partner_id` bigint(20) NOT NULL,
  `password` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `date_created` datetime DEFAULT NULL,
  `last_updated` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique-email` (`partner_id`,`email`),
  UNIQUE KEY `users_Uuid` (`uuid`),
  KEY `idx_013_partner_id_uuid` (`partner_id`,`uuid`),
  KEY `idx_014_uuid` (`uuid`),
  CONSTRAINT `FKB2D9FEBE725C505E` FOREIGN KEY (`partner_id`) REFERENCES `partner` (`id`),
  CONSTRAINT `fk_046_partner` FOREIGN KEY (`partner_id`) REFERENCES `partner` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


CREATE TABLE IF NOT EXISTS `user_properties` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `version` bigint(20) NOT NULL,
  `date_created` datetime DEFAULT NULL,
  `last_updated` datetime DEFAULT NULL,
  `upkey` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `user_id` bigint(20) DEFAULT NULL,
  `security_level` int(11) NOT NULL,
  `_content` longtext COLLATE utf8_unicode_ci NOT NULL,
  `class` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `date_value` datetime DEFAULT NULL,
  `integer_value` bigint(20) DEFAULT NULL,
  `double_value` double DEFAULT NULL,
  `string_value` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `uuid` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_004_uuid` (`uuid`),
  KEY `idx_005_string_value` (`upkey`,`string_value`),
  KEY `idx_006_integer_value` (`upkey`,`integer_value`),
  KEY `idx_007_double_value` (`upkey`,`double_value`),
  KEY `idx_008_date_value` (`upkey`,`date_value`),
  KEY `idx_key_value_user_upkey_string` (`user_id`,`upkey`,`string_value`),
  CONSTRAINT `FK_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

【问题讨论】:

  • 我认为优先考虑的是速度,而不是事务消耗多少 IOPS!
  • @Shadow 我只想知道我的速度情况的瓶颈是什么 - 我应该增加/改变什么以使其更快? IOPS 未充分利用,CPU 未充分利用,RAM 还可以 - 所以没有明确的候选者,我很困惑下一步该做什么..
  • @Shadow 这几乎是普通的insert into user_properties from select * from...。我在 3 个应用程序线程中为每个事务批量插入约 10-50K 条记录。我不做 COPY,它是来自 Java 的常规 SQL 语句。除了此次插入之外,数据库中没有其他活动。
  • 你测量过你占用了多少驱动带宽吗?您可以拥有足够的 IOPS,但如果您使用了带宽容量,那么该驱动器就差不多了。
  • 在会话级别开始数据传输之前是否关闭外键检查?

标签: mysql database performance amazon-web-services amazon-rds


【解决方案1】:

您需要iduuid 吗?我认为不会。

一张桌子需要 3 个 UNIQUE 键吗?我想不是。 (记住PRIMARY KEYUNIQUE。)

uuid 在表变​​得很大时有一些非常糟糕的 I/O 属性。重新考虑您对它们的使用。 uuid 上的索引是非常随机的。当索引(或表)变得太大而无法放入 buffer_pool 时,提取往往涉及 I/O 而不是被缓存。对于 350M 行和 16GB RAM,我怀疑性能问题的很大一部分是由于 uuid。

user_properties 是一个“键值”存储,对吗?这种模式设计模式很糟糕。什么是典型的SELECT?我怀疑是这样的:

SELECT ..._value FROM user_properties
    WHERE user_id = '...'
      AND upkey = '...';

假设这是正确的,性能可以通过具有一些改进

PRIMARY KEY(user_id, upkey, id)

这会将给定用户的键值对“聚集”在一个位置(可能是 1-2 个块),从而加快获取速度。

更多关于evils of key-value 和改进建议。
更多关于evils of UUIDs

【讨论】:

  • uuid 是出于安全原因引入的,ID 太容易暴力破解。我不需要 ID,自动增量已删除,现在为 NULL。典型的选择是:1.查找用户的属性-您提到的案例,2.按属性查找用户-upkey/string_value。我的问题通常不是关于表设计如何臭(它确实,我确认!),而是当服务器看起来负载不足时如何识别瓶颈。一个很好的怀疑是驱动吞吐量为 90Mb/s。嗯,是的,看起来这个瓶颈最好用好的模式来解决,而不是 RAID 或 smth。你怎么看?
  • 架构及其索引是一个很大的瓶颈。 RDS不使用SSD吗?如果是这样,这比旋转驱动器要好得多,即使使用 RAID 条带化也是如此。我无法确定您现在是否受 I/O 限制;如果你是,那可能是因为 UUID——这可以通过更多的 RAM 来克服(直到表再次变得太大)。
  • 对于 upkey+string --> user_id,INDEX(upkey, string_value, user_id) 会是“覆盖索引”吗?如果是这样,那将是一个小而容易的加速。
  • "看起来负载不足" -- 一个 mysql/mariadb 线程不会使用超过一个 CPU 内核。你能解释一下为什么写比读多吗?你有什么sync_binlog、innodb_flush_log_at_trx_commit、innodb_double_write、innodb_%_io_threads?
  • 写入多于读取:基本上因为我们现在关心的是插入速度,所以这是问题所在。我们希望它更快并且看起来如何。读取速度正好满足我们的需求。我们使用 3 个线程批量插入每个事务 10k-50k 用户道具。
猜你喜欢
  • 2017-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多