我的 MySQL 数据库有超过 3.5 亿行,并且还在增长。它现在的大小是 32GB。我正在使用 SSD 和大量 RAM,但想寻求建议以确保我使用的是适当的索引。
CREATE TABLE `qcollector` (
`key` bigint(20) NOT NULL AUTO_INCREMENT,
`instrument` char(4) DEFAULT NULL,
`datetime` datetime DEFAULT NULL,
`last` double DEFAULT NULL,
`lastsize` int(10) DEFAULT NULL,
`totvol` int(10) DEFAULT NULL,
`bid` double DEFAULT NULL,
`ask` double DEFAULT NULL,
PRIMARY KEY (`key`),
KEY `datetime_index` (`datetime`)
) ENGINE=InnoDB;
show index from qcollector;
+------------+------------+----------------+--------------+-------------+-----------+-- -----------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| qcollector | 0 | PRIMARY | 1 | key | A | 378866659 | NULL | NULL | | BTREE | | |
| qcollector | 1 | datetime_index | 1 | datetime | A | 63144443 | NULL | NULL | YES | BTREE | | |
+------------+------------+----------------+--------------+-------------+-----------+------ -------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.03 sec)
select * from qcollector order by datetime desc limit 1;
+-----------+------------+---------------------+---------+----------+---------+---------+--------+
| key | instrument | datetime | last | lastsize | totvol | bid | ask |
+-----------+------------+---------------------+---------+----------+---------+---------+--------+
| 389054487 | ES | 2012-06-29 15:14:59 | 1358.25 | 2 | 2484771 | 1358.25 | 1358.5 |
+-----------+------------+---------------------+---------+----------+---------+---------+--------+
1 row in set (0.09 sec)
一个典型的慢查询(全表扫描,这个查询需要3-4分钟):
explain select date(datetime), count(lastsize) from qcollector where instrument = 'ES' and datetime > '2011-01-01' and time(datetime) between '15:16:00' and '15:29:00' group by date(datetime) order by date(datetime) desc;
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+
| 1 | SIMPLE | qcollector | ALL | datetime_index | NULL | NULL | NULL | 378866659 | Using where; Using temporary; Using filesort |
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+
最佳答案
一些想法供您考虑:
覆盖索引(即包含查询中引用的所有列的索引)可能会有所帮助。这样的索引将需要更多的磁盘(SSD?)空间,但它将消除 MySQL 访问数据页以查找不在索引中的列的值的必要性。
ON qcollector (datetime,instrument,lastsize)
或ON qcollector (instrument,datetime,lastsize)
您真的需要从计数中排除
lastsize
值为 NULL 的行吗?您可以返回所有行的计数吗?如果您可以改为返回COUNT(1)
或SUM(1)
,则查询不需要引用lastsize
列,因此索引中不需要它来使其成为覆盖索引。COUNT(lastsize)
表达式等效于SUM(IF(lastsize IS NULL,0,1))
您是否需要在日期时间范围内只有 NULL
lastsize
值时返回日期,或者是否可以排除具有 NULLlastsize
的所有行?也就是说,您可以包含一个谓词吗AND lastsize 不为空
在您的查询中?
这些可能对某些人有帮助。
我认为最大的问题是 TIME(datetime)
表达式上的谓词不可搜索。也就是说,MySQL 不会对这些使用索引范围扫描操作。裸 datetime
列上的谓词是可搜索的...这就是 EXPLAIN 将 datetime_index 显示为可能的键的原因。
另一个大问题是查询正在对派生表达式执行 GROUP BY
和 ORDER BY
操作,这将需要 MySQL 生成中间结果集(作为临时 MyISAM 表),然后处理该结果集。当有很多行要处理时,这可能会很繁重。
就表更改而言,我会考虑使用单独的 DATE 和 TIME 列,并使用 TIMESTAMP 数据类型代替 DATETIME(如果您需要将日期和时间存储在一起)。我会重写查询以引用裸 DATE 和裸 TIME 列,并考虑添加一个覆盖索引,其中包括重写查询中引用的所有列,前导列是具有最高基数的列(并且在查询。)
关于mysql - 为查询优化 MySQL 索引(交易报价数据数据库),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11513966/