2016-02-26 72 views
2

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

user_properties表格描述了附属于用户的道具的“地图”。 upkey是关键,string_value,integer_value等是每种类型的值; STRING,DATE,INTEGER,DOUBLE。索引也是按类型的。

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

问题是我们只能达到2500个写入IOPS和500-1000个读取IOPS。队列深度平均保持在〜7。 MySQL服务器CPU使用率保持在20-30%,永远不会达到60%。 应用程序似乎向MySQL提供足够的数据:我们将类似的数据文件提供给数据库,并查看处理时间随着表大小的增加而增加。 大部分时间应用程序都等待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; 
+0

我认为速度是重中之重,而不是交易如何消耗IOPS! – Shadow

+0

@Shadow我只是想知道我的速度情况有什么瓶颈 - 我应该增加/更改哪一个以使速度更快?IOPS没有得到充分利用,CPU使用不足,RAM没问题 - 所以没有明确的候选人,我很困惑接下来要做什么.. – snowindy

+0

@Shadow从select * from ...'插入到user_properties中几乎是纯粹的。我在每个事务中按3个应用程序线程批量插入〜10-50K条记录。我不会做COPY,它是来自Java的常规SQL语句。除此插入之外,没有其他活动处于数据库中。 – snowindy

回答

2

你需要同时iduuid?我想不是。

你需要3 UNIQUE表的钥匙吗?我想不是。 (记住一个PRIMARY KEYUNIQUE。)

uuid当表变得巨大时,它有一些非常糟糕的I/O属性。重新考虑你对它们的使用。 uuid上的索引是非常随意的。当索引(或表)变得太大而不适合buffer_pool时,抓取往往涉及I/O而不是被缓存。随着350M行和16GB的RAM,我怀疑性能问题的一个重要部分是由于uuids。

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

+0

uuid出于安全原因,ID很容易蛮力。我不需要ID,自动增量被删除,现在它是NULL。 典型的选择是:1.找到您提到的用户属性 - 2.通过属性查找用户 - upkey/string_value。 我的问题一般不是关于餐桌设计的臭味(它确实如此,我确认!),而是如何在服务器看起来像欠载时识别瓶颈。一个好的怀疑是驱动90Mb/s的吞吐量。好吧,它看起来像这个瓶颈是最好的解决方案,好的架构,而不是RAID或水手。你怎么看? – snowindy

+0

模式及其索引是一个很大的瓶颈。 RDS不使用SSD吗?如果是这样,即使使用RAID分条,这比旋转驱动器要好得多。我无法确定您现在是否受I/O限制;如果你是这样,可能是因为UUID - 这可以通过更多的RAM来克服(直到表再次变得太大)。 –

+0

对于upkey + string - > user_id,'INDEX(upkey,string_value,user_id)'是一个“覆盖索引”?如果这样做会是一个小而简单的加速。 –