【发布时间】:2016-11-10 04:51:08
【问题描述】:
总的来说,日期范围分区和内存配置实现了我的目标。
我需要增加分配给 innodb_buffer_pool_size 的内存,因为默认的 8M 太低了。 Rick James 推荐 70% of RAM 进行此设置,他有很多很棒的信息。
Edlerd 对这两个建议都是正确的 :-)
我将数据拆分为每月分区,然后运行 6,000 行响应查询,最初需要 6 到 12 秒。它现在在不到一秒的时间内完成 (.984/.031)。我使用默认的 innodb 缓冲区大小(innodb_buffer_pool_size = 8M)运行它,以确保它不仅仅是内存增加。
然后我设置 innodb_buffer_pool_size = 4G 并以 .062/.032 的更好响应运行查询。
我还想提一下,增加内存还提高了我的 Web 应用程序和服务的整体速度,这些应用程序和服务接收和写入该表的消息,我对这个配置设置产生的巨大差异感到震惊。我的 Web 服务器的第一个字节时间 (TTFB) 现在几乎与 MySQL Workbench 相当,有时会达到 20 秒。
我还发现slow query log file 是识别问题的绝佳工具,在那里我看到它表明我的 innodb_buffer_pool_size 很低并且突出显示了所有性能不佳的查询。这也确定了我需要索引其他表的区域。
编辑 2016-11-12 解决方案
我正在重构一个记录遥测数据的大表,它已经运行了大约 4-5 个月,并且已经生成了大约 4-5 个月。 5400 万条记录,平均行大小约为。 380 字节。
我开始发现我的一个原始数据查询在 24 小时内返回设备的所有日志时出现了一些性能滞后。
最初我以为是索引,但我认为是 MySQL 需要处理的 I/O 量。一个典型的 24 小时查询将包含 2.2k 3k 到 9k 条记录,我实际上希望支持大约 7 天的导出。
我在数据库性能调优方面没有经验,所以仍然只是在学习。我正在考虑一些策略。
- 根据原始数据查询调整复合索引,尽管我认为我的索引没问题,因为解释计划显示 100% 的命中率。
- 考虑创建一个覆盖索引以包含所有需要的行
- 按日期实现范围分区: a) 保留每月分区。例如。过去 6 个月 b) 将任何较旧的内容移至存档表。
- 使用原始数据创建一个单独的表(垂直分区)并将其与主查询表的 ID 连接。不确定这是我的问题,因为我的索引正在工作。
- 更改我的查询以分批提取数据并限制,然后按创建的日期限制 X 排序并继续,直到不再返回任何记录。
- 查看服务器配置
1,2(索引): 我会用我的查询来修改我的索引,但我认为我在这里很好,因为 Explain 显示 100% 命中,除非我读错了。
我会在重建时尝试使用覆盖索引,但我如何确定设置错误的连锁效应?例如。插入速度受到影响。
如何最好地监控我的表在实时环境中的性能?
编辑:我刚刚开始使用slow log file,它看起来是查找问题的好工具,我想performance_schema 上的查询可能是另一种选择?
3(分区): 我已经阅读了一些关于分区的内容,但不确定我的数据大小是否会产生很大的不同。
Rick James suggests >1M 记录,我有 54M 并且希望在归档之前保留大约 300M,我的表是否足够复杂以受益?
我必须自己测试一下,因为我没有使用任何这些东西的经验,而且这对我来说都是理论上的。如果它不适合我的需求,我只是不想走这条路。
4(通过“加入”详细信息表进行垂直分区):我认为没有表扫描问题并且我需要所有行,所以我不确定这种技术是否有用.
5(使用限制并再次获取):如果我在单个请求中使用较少的时间,这会释放服务器吗?我会以同一连接上的更多命令为代价获得更好的 I/O 吞吐量吗?
6(查看配置):另一部分是查看安装 MySQL 时使用的默认非开发人员配置,也许有一些可以调整的设置? :-)
感谢阅读,渴望听到任何和所有建议。
以下仅供参考:
表格:
CREATE TABLE `message_log` (
`db_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`db_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created` datetime DEFAULT NULL,
`device_id` int(10) unsigned NOT NULL,
`display_name` varchar(50) DEFAULT NULL,
`ignition` binary(1) DEFAULT NULL COMMENT 'This is actually IO8 from the falcom device',
`sensor_a` float DEFAULT NULL,
`sensor_b` float DEFAULT NULL,
`lat` double DEFAULT NULL COMMENT 'default GPRMC format ddmm.mmmm \n',
`lon` double DEFAULT NULL COMMENT 'default GPRMC longitude format dddmm.mmmm ',
`heading` float DEFAULT NULL,
`speed` float DEFAULT NULL,
`pos_validity` char(1) DEFAULT NULL,
`device_temp` float DEFAULT NULL,
`device_volts` float DEFAULT NULL,
`satellites` smallint(6) DEFAULT NULL, /* TINYINT will suffice */
`navdist` double DEFAULT NULL,
`navdist2` double DEFAULT NULL,
`IO0` binary(1) DEFAULT NULL COMMENT 'Duress',
`IO1` binary(1) DEFAULT NULL COMMENT 'Fridge On/Off',
`IO2` binary(1) DEFAULT NULL COMMENT 'Not mapped',
`msg_name` varchar(20) DEFAULT NULL, /* Will be removed */
`msg_type` varchar(16) DEFAULT NULL, /* Will be removed */
`msg_id` smallint(6) DEFAULT NULL,
`raw` text, /* Not needed in primary query, considering adding to single table mapped to this ID or a UUID correlation ID to save on @ROWID query */
PRIMARY KEY (`db_id`),
KEY `Name` (`display_name`),
KEY `Created` (`created`),
KEY `DeviceID_AND_Created` (`device_id`,`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DeviceID_AND_Created 是主索引。我需要 PK 聚集索引,因为我在汇总表中使用记录 ID,该记录 ID 跟踪给定设备的最后一条消息。创建的将是分区列,所以我猜它也会添加到 PK 集群中?
查询:
SELECT
ml.db_id, ml.db_created, ml.created, ml.device_id, ml.display_name, bin(ml.ignition) as `ignition`,
bin(ml.IO0) as `duress`, bin(ml.IO1) as `fridge`,ml.sensor_a, ml.sensor_b, ml.lat, ml.lon, ml.heading,
ml.speed,ml.pos_validity, ml.satellites, ml.navdist2, ml.navdist,ml.device_temp, ml.device_volts,ml.msg_id
FROM message_log ml
WHERE ml.device_id = @IMEI
AND ml.created BETWEEN @STARTDATE AND DATE_ADD(@STARTDATE,INTERVAL 24 hour)
ORDER BY ml.db_id;
这将返回给定 24 小时期间的所有日志,目前大约为 24 小时。 3k 到 9k 行,平均行大小 381 字节,一旦我删除了 TEXT 字段之一(原始)
【问题讨论】:
-
请提供一些滞后数字以及查询计划以显示正在发生的事情
-
@SamiKuhmonen 嗨,修改我的回复。刚刚查看了慢查询日志,发现数据比我想象的要多得多,所以输出较慢可能是由于某些设备产生的数据较多。我已经更新了解释计划,虽然命中率差不多。我可以使用其他指标吗?我正在将此表导入 DEV,并将尽快创建一些分区。
-
为什么不发布解决方案作为答案,而不是将它们编辑到问题中?这个问题现在看起来很混乱。
标签: mysql indexing database-performance partitioning