基本的MySQL查询非常慢。我正确索引我的桌子吗?

时间:2018-03-28 20:53:18

标签: mysql indexing

我目前正在优化一个非常大的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是两个表相关的字段。 metar_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),除了metar_records之外没有auto_increment字段,没有任何索引。执行SELECT COUNT(*) FROM metar_test;最多持续0.02秒 ,而SELECT COUNT(*) FROM metar_records;大约需要1分18秒才能完成。

据我所知,拥有这么大的表会导致一些较长的查询时间,但metar_records只比metar_test大3.36倍 - 为什么{{1}之间存在如此大的差异查询这两个表?我并不是特别精通数据存储,但这种差异似乎对我来说意外大。

如何改进索引以优化大表大小?是否可以从这里减少查询持续时间?

3 个答案:

答案 0 :(得分:0)

您可以尝试:

select count(stationID) 
from metar_records

这将使查询优化器使用stationID的索引,因此读取较少的数据作为读取完整数据的count(*)。

答案 1 :(得分:0)

我会以这种方式重建你的桌子。

站。 我是汽车公司。 StationId char(4)独一无二 其余...

Metar_records 我是汽车公司 StationId引用stations.id 其余...

这样你的密钥长度就会变小和数字。会提升你的表现。

答案 2 :(得分:0)

您可能已启用“查询缓存”。这使得第二次运行完全相同的查询非常快。要正确计算查询时间,请执行两次并执行第二次计时:

SELECT SQL_NO_CACHE ...

COUNT(*)是计算行的常用模式。 COUNT(col)速度较慢,因为它需要检查每个col是否为NOT NULL

你的大桌上有3 INDEXes;你只需要一个:

PRIMARY KEY(stationID, zdatetime)

并且,通过这种方式进行聚类,几个可能的查询将运行得更快。

请使用SHOW CREATE TABLE;它比DESCRIBE更具描述性。

您应该使用ENGINE=InnoDB,而不是ENGINE=MyISAM(请参阅SHOW CREATE TABLE)。

SELECT COUNT(*) ...不是一个非常常见的查询;你不应该花很多钱来运行它的速度。

PARTITIONing不太可能有助于提高效果。让我们看看你的更多问题 - 仔细检查我的说法。 MySQL没有并行处理,即使对于PARTITIONed表也是如此。

还从Stations表中抛出id AUTO_INCREMENT;相反,请PRIMARY KEY(stationID)