我的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 |
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+
答案 0 :(得分:1)
在列上使用date
和time
函数时,无法有效使用索引。您还可以将日期和时间存储在单独的列中并对其进行索引,但这会占用更多存储空间。
您可能还需要考虑添加多列索引。 (instrument, datetime)
上的索引可能会对您有所帮助。
答案 1 :(得分:1)
您可以考虑几个想法:
覆盖索引(即包含查询中引用的所有列的索引)可能有所帮助。这样的索引将需要更多的磁盘(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
值时,是否需要返回日期,或者是否可以排除所有具有NULL lastsize
的行?也就是说,你可以包含一个像
AND lastsize IS NOT NULL
?
这些可能有所帮助。
我认为最大的问题是TIME(datetime)
表达式的谓词不可理解。也就是说,MySQL不会对那些使用索引范围扫描操作。裸datetime
列上的谓词是可搜索的......这就是EXPLAIN将datetime_index显示为可能的键的原因。
另一个大问题是查询正在对派生表达式执行GROUP BY
和ORDER BY
操作,这将要求MySQL生成中间结果集(作为临时MyISAM表) ,然后处理该结果集。当有很多行要处理时,这可能会带来很多繁重的工作。
就表格更改而言,我会考虑使用单独的DATE和TIME列,并使用TIMESTAMP数据类型代替DATETIME(如果需要将日期和时间存储在一起)。我会重写查询以引用裸DATE和裸TIME列,并考虑添加覆盖索引,其中包括重写查询中引用的所有列,前导列是具有最高基数的列(并且具有最高选择性谓词)查询。)