MySQL数据库变慢

问题描述 投票:1回答:1

我需要一些帮助来解决性能问题。存在约800万条记录后,包含单个表的METAR(航空天气报告)数量不断增加的数据库正在放缓。尽管正在使用索引。可以通过重建索引来恢复性能,但这确实很慢,并且会使数据库脱机,因此我只能删除表并重新创建表(丢失最后几周的数据)。

无论是运行查询来尝试检索实际元数据还是执行简单的select count(*),行为都是相同的。

表创建语法如下:

CREATE TABLE `metars` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `tstamp` timestamp NULL DEFAULT NULL,
  `metar` varchar(255) DEFAULT NULL,
  `icao` char(7) DEFAULT NULL,
  `qnh` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `timestamp` (`tstamp`),
  KEY `icao` (`icao`),
  KEY `qnh` (`qnh`),
  KEY `metar` (`metar`)
) ENGINE=InnoDB AUTO_INCREMENT=812803050 DEFAULT CHARSET=latin1;

[最多约800万条记录,select count(*)在约500毫秒内返回。然后逐渐增加,目前又达到1400万条记录,计数需要3到30秒。我很惊讶地看到,在解释计数查询时,它使用时间戳作为索引,而不是主键。使用主键只需几毫秒即可返回记录数:

mysql> explain select count(*) from metars;
+----+-------------+--------+-------+---------------+-----------+---------+------+----------+-------------+
| id | select_type | table  | type  | possible_keys | key       | key_len | ref  | rows     | Extra       |
+----+-------------+--------+-------+---------------+-----------+---------+------+----------+-------------+
|  1 | SIMPLE      | metars | index | NULL          | timestamp | 5       | NULL | 14693048 | Using index |
+----+-------------+--------+-------+---------------+-----------+---------+------+----------+-------------+
1 row in set (0.00 sec)

强制它使用主索引甚至更慢:

mysql> select count(*) from metars use index(PRIMARY);
+----------+
| count(*) |
+----------+
| 14572329 |
+----------+
1 row in set (37.87 sec)

奇怪的是,典型的用例查询是获取距特定时间点最近的机场的天气,尽管比简单的计数更为复杂,但该机场的性能仍然很好:

mysql> SELECT qnh, metar from metars WHERE icao like 'KLAX' ORDER BY ABS(TIMEDIFF(tstamp, STR_TO_DATE('2019-10-10 00:00:00', '%Y-%m-%d %H:%i:%s'))) LIMIT 0,1;
+------+-----------------------------------------------------------------------------------------+
| qnh  | metar                                                                                   |
+------+-----------------------------------------------------------------------------------------+
| 2980 | KLAX 092353Z 25012KT 10SM FEW015 20/14 A2980 RMK AO2 SLP091 T02000139 10228 20200 56007 |
+------+-----------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

我在这里做错了什么?

mysql performance
1个回答
0
投票

InnoDB通过遍历某些索引来执行普通的COUNT(*)。它希望使用最小的索引,因为这将需要触摸块的租赁数量。

PRIMARY KEY与数据聚集在一起,因此索引实际上是最大的。

您使用的是哪个版本? TIMESTAMP有所改变。也许这解释了为什么使用tstamp而不是qnh

如果要通过使用DELETE清除旧数据,请参见http://mysql.rjweb.org/doc.php/partitionmaint以获取更快的方法。

我假设数据是静态的;那是从来没有UPDATEd吗?考虑建立和维护一个汇总表,也许按日期索引。这一天可能有各种各样的计数。然后,从该表中获取数据将比命中原始数据快得多。更多:http://mysql.rjweb.org/doc.php/summarytables

© www.soinside.com 2019 - 2024. All rights reserved.