1.09亿条记录的MyISAM表查询过慢,如何优化?
你当前查询慢的根本原因是索引不匹配查询模式,命中单列索引后需要大量回表随机IO+额外排序,导致耗时高。下面是可落地的优化方案,按优先级从高到低排列:
1. 索引优化(改动最小,见效最快)
1.1 建立匹配查询的覆盖联合索引
你现在的查询模式是:过滤变量/站点+按自增ID倒序+返回时间、数值两个字段,针对这两个查询场景直接建覆盖索引,不需要回表,也不需要额外排序:
- 针对单
var_name查询:
ALTER TABLE INVIEW_LOGS ADD INDEX idx_varname_id_cover (var_name, id DESC, dia_hora, valor);
- 针对
prf_station_id + var_name双条件查询:
ALTER TABLE INVIEW_LOGS ADD INDEX idx_station_varname_id_cover (prf_station_id, var_name, id DESC, dia_hora, valor);
覆盖索引可以直接在索引层完成过滤、排序、数据返回,完全避免回表的随机IO开销,正常情况下查询耗时可以降到1秒以内。
1.2 用更小的字段代替var_name做查询条件
var_name是125字节的char类型,索引体积大查询效率低,你表中已经有唯一标识变量的iws_var_id(3字节mediumint),建议业务层提前维护变量名和iws_var_id的映射关系,查询时用iws_var_id代替var_name做过滤,索引体积可以缩小90%以上,查询速度还能再提升数倍。
2. 业务层缓存(性能提升最显著,适配你的只读场景)
你的实例只有夜间短时间写入,日常全是读请求,且业务固定查询6-7个变量的最新1万条数据,完全可以做冷缓存:
- 夜间增量数据写入完成后,异步执行查询把这6-7个变量的最新1万条结果写入一张独立的小表,或者直接写入Redis缓存
- 前端查询直接请求缓存/小表,耗时可以降到毫秒级,完全不需要查询1亿条的大表
3. 表结构与存储优化
3.1 时序数据分区
你的数据是带时间戳的时序数据,按dia_hora字段做天/月分区,查询最新数据时只会扫描最近的分区,不需要遍历全表,后续数据持续增长也不会出现性能衰减。
3.2 存储引擎与配置优化
- 如果你继续用MyISAM,把
key_buffer_size调整到服务器内存的50%~70%,尽量把全部索引都加载到内存中,避免磁盘IO - 也可以考虑切回InnoDB,将
innodb_buffer_pool_size调整到服务器内存的70%~80%,InnoDB的聚簇索引和缓冲池在只读场景下性能不弱于MyISAM,还不会出现MyISAM表损坏的问题
4. 查询逻辑优化
查询时可以额外加时间范围过滤条件,比如你知道某个变量的1万条数据跨度不会超过7天,就加上AND dia_hora >= DATE_SUB(NOW(), INTERVAL 7 DAY),可以进一步减少需要扫描的数据量。
内容的提问来源于stack exchange,提问作者Eduardo Luís
相关产品推荐
相关产品推荐

