【发布时间】:2018-04-03 10:22:42
【问题描述】:
我目前正在优化一个非常大的 MySQL 数据库,我正在围绕它构建一个基于 Web 的查询界面。
数据库将有两个表。第一张表已经优化(我相信),其中包含有关美国 950 个气象数据观测站的信息:
Description for: stations (950 records)
+-----------+------------+--------+-------+---------+----------------+
|Field |Type | NULL |KEY | Default | Extra |
+-----------+------------+--------+-------+---------+----------------+
|id |INT |NO |PRI |NULL |auto_increment |
|stationID |char(4) |NO |PRI |NULL | |
|name |varchar(16) |YES | |NULL | |
|state |char(2) |YES |MUL |NULL | |
|lat |float(6,2) |YES | |NULL | |
|lon |float(6,2) |YES | |NULL | |
|elev |INT |YES | |NULL | |
+-----------+------------+--------+-------+---------+----------------+
另一张表包含从 2014 年到 2017 年在这些站点收集的观测数据(已构建,未优化):
Description for: metar_records (359786049 records)
+-----------+------------+--------+-------+---------+----------------+
|Field |Type | NULL |KEY | Default | Extra |
+-----------+------------+--------+-------+---------+----------------+
|auto_id |INT |NO |PRI |NULL |auto_increment |
|stationID |char(4) |NO |MUL |0 | |
|zdatetime |datetime |NO | |NULL | |
|ldatetime |datetime |NO | |NULL | |
|temp |tinyint(4) |YES | |NULL | |
|dew |tinyint(4) |YES | |NULL | |
|wspd |tinyint(3) |YES | |NULL | #unsigned |
|wdir |tinyint(3) |YES | |NULL | #unsigned |
|wgust |tinyint(3) |YES | |NULL | #unsigned |
|VRB |char(3) |YES | |NULL | |
+-----------+------------+--------+-------+---------+----------------+
其中 stationID 是两个表相关的字段。 meta_records 在('stationID', 'zdatetime') 上有一个唯一索引。 metar_records 表索引列表:
+-------------+--------+---------+------------+-----------+-----------+----------+
|Table |Non_UNQ |Key_name |Seq_in_index|Column_name|Cardinality|Index_type|
+-------------+--------+---------+------------+-----------+-----------+----------+
|metar_records|0 |PRIMARY |1 |auto_id |358374698 |BTREE |
|metar_records|0 |sz_date |1 |stationID |820079 |BTREE |
|metar_records|0 |sz_date |2 |zdatetime |358374698 |BTREE |
|metar_records|1 |stationID|1 |stationID |598288 |BTREE |
+-------------+--------+---------+------------+-----------+-----------+----------+
这是我真正感到困惑的地方:我还有一个测试表(称为 metar_test),除了没有 auto_increment 字段之外,它与 metar_records 相同,并且有没有任何索引。 SELECT COUNT(*) FROM metar_test; 的执行最多持续 0.02 秒,而 SELECT COUNT(*) FROM metar_records; 大约需要 1 分 18 秒才能完成。
我知道拥有这么大的表会导致查询时间较长,但 metar_records 仅比 metar_test 大 3.36 倍——为什么两者的 SELECT COUNT(*) ... 查询之间存在如此大的差异表?我对数据存储不是特别精通,但这种差异对我来说似乎出乎意料的大。
如何改进索引以优化大表大小?是否可以从这里减少查询持续时间?
【问题讨论】:
-
索引根本不应该影响这些查询;索引有助于在索引字段上过滤/加入/分组的查询;但通常不应对未过滤/加入/分组的选择查询产生负面影响。我建议仔细检查表格之间的差异;包括字符集、排序规则和存储引擎。
-
大表中当前有多少行?它会增长多少?你考虑过“分区”吗? (见dev.mysql.com/doc/refman/5.7/en/partitioning.html)
-
@Used_By_Already 359786049 行在较大的表中。不知道它是否会增长。我基本上是为面试组合构建它,但我还没有决定是否要维护它以使其保持最新。分区是我将不得不探索的东西。谢谢推荐!
-
分区不会加速
select count(*),除非 dbms 也支持并行处理。select count(*)正在进行表扫描,因此磁盘访问速度可能是瓶颈(并且可以解释为什么测试表和真实表之间的差异)。