Nic*_*las 5 mysql indexing partitioning database-performance
我需要增加分配给innodb_buffer_pool_size的内存,因为默认的8M太低了.Rick James推荐70%的RAM用于此设置,他有很多很棒的信息.
Edlerd对两个建议都是正确的:-)
我将数据拆分为月分区,然后运行6,000行响应查询,最初需要6到12秒.它现在在不到一秒钟内完成(.984/.031).我使用默认的innodb缓冲区大小(innodb_buffer_pool_size = 8M)来运行它,以确保它不仅仅是内存增加.
然后我设置innodb_buffer_pool_size = 4G并以更好的响应运行查询.062/.032.
我还想提一下,增加内存也提高了我的Web应用程序和服务的整体速度,它接收和写入消息到这个表,我很惊讶这个配置设置有多大的不同.我的网络服务器的第一个字节时间(TTFB)现在几乎与MySQL Workbench相当,有时会达到20秒.
我还发现慢查询日志文件是识别问题的一个很好的工具,我在那里看到它表明我的innodb_buffer_pool_size很低并且突出了所有表现不佳的查询.这也确定了我需要索引其他表的区域.
我正在重构一个记录遥测数据的大型表,它已经运行了大约4-5个月并且已经产生了大约.平均行数约为5400万条记录.380个字节.
我已经开始看到我的一个原始数据查询的性能滞后,它会在24小时内返回设备的所有日志.
最初我认为它是索引,但我认为这是MySQL需要处理的I/O量.一个典型的24小时查询将包含2.2k 3k到9k记录,我实际上想支持大约7天的导出.
我没有数据库性能调优的经验,所以仍然只是学习绳索.我正在考虑一些策略.
1,2(INDEXES): 我会用我的查询修改我的索引,但我认为我很好,因为Explain显示100%命中,除非我读错了.
我会在重建时尝试覆盖索引,但是如何确定设置错误的效果呢?EG插入速度受到影响.
如何在实时环境中最好地监控桌子的性能?
编辑:我刚刚开始使用慢速日志文件,它看起来像是一个很好的查找问题的工具,我想在performance_schema上查询可能是另一种选择?
3(PARTITIONING): 我已经阅读了一些关于分区的内容,并且不确定我的数据大小是否会产生很大的差异.
Rick James提出了大约1M的记录,我是54M,并希望在归档之前保持300M左右,我的桌子是否足够复杂?
我必须自己测试一下,因为我没有任何这方面的经验,这对我来说都是理论上的.如果它不适合我的需要,我只是不想走这条路.
4(通过'加入'细节表进行垂直分区):我不认为我有表扫描问题而且我需要所有行,所以我不确定这种技术是否有益.
5(使用限制并再次获取):如果我在一个请求中使用较少的时间,这会释放服务器吗?我是否会在同一连接上以更多命令为代价看到更好的I/O吞吐量?
6(查看配置):另一部分是审查安装MySQL时使用的默认非开发人员配置,也许有一些设置可以调整?:-)
感谢阅读,热衷于听取任何和所有建议.
以下FYI:
表:
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;
Run Code Online (Sandbox Code Playgroud)
DeviceID_AND_Created是主索引.我需要PK聚簇索引,因为我在摘要表中使用记录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;
Run Code Online (Sandbox Code Playgroud)
这将返回给定24小时的所有日志,此时此时间约为.3k到9k行,平均行大小为381字节,一旦删除其中一个TEXT字段(原始),将减少
按日期实施范围分区: a) 保留每月分区。例如,过去 6 个月 b) 将任何较旧的内容移至存档表。
这是一个很好的主意。我猜想所有写入都将位于最新的分区中,并且您将仅查询最近的数据。您总是希望数据和索引适合内存。所以读取时没有磁盘 I/O。
根据您的使用情况,每周使用一个分区甚至可能是明智的。那么您只需在内存中保留最多两周的数据即可读取过去 7 天的数据。
如果您使用 innodb 作为引擎,您可能还需要调整缓冲区大小(即 innodb_buffer_pool_size),或者在使用 myisam 引擎时调整 myisam_key_cache。
另外,向数据库机器添加内存通常会有所帮助,因为操作系统可以将数据文件存储在内存中。
如果写入量很大,您还可以调整其他选项(即使用 innodb_log_buffer_size 将写入持久化到磁盘的频率)。这是为了让脏页在内存中保留更长时间,以避免过于频繁地将它们写回磁盘。