mysql - 为查询优化 MySQL 索引(交易报价数据数据库)

标签 mysql optimization indexing create-table

我的 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 值时返回日期,或者是否可以排除具有 NULL lastsize 的所有行?也就是说,您可以包含一个谓词吗

    AND lastsize 不为空

在您的查询中?

这些可能对某些人有帮助。


我认为最大的问题是 TIME(datetime) 表达式上的谓词不可搜索。也就是说,MySQL 不会对这些使用索引范围扫描操作。裸 datetime 列上的谓词是可搜索的...这就是 EXPLAIN 将 datetime_index 显示为可能的键的原因。

另一个大问题是查询正在对派生表达式执行 GROUP BYORDER BY 操作,这将需要 MySQL 生成中间结果集(作为临时 MyISAM 表),然后处理该结果集。当有很多行要处理时,这可能会很繁重。


就表更改而言,我会考虑使用单独的 DATE 和 TIME 列,并使用 TIMESTAMP 数据类型代替 DATETIME(如果您需要将日期和时间存储在一起)。我会重写查询以引用裸 DATE 和裸 TIME 列,并考虑添加一个覆盖索引,其中包括重写查询中引用的所有列,前导列是具有最高基数的列(并且在查询。)

关于mysql - 为查询优化 MySQL 索引(交易报价数据数据库),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11513966/

相关文章:

MySQL 查询 - 无法确定如何编写特定查询

java - 在SQL中使用一个命令 - 我需要将单词 'Cars' 的所有实例更改为 'Zip-Cars' ,这包括将 'Cars 2' 更改为 'Zip-Cars 2'

mysql - apache camel 路由拆分 sql 结果

r - 最小化带有约束的 R 中的多元函数

与列表相关的java难题

mysql - OR 其他条件之间的冲突

c++ - 从字符串中获取 IPv4 地址的最快方法

objective-c - ios 8 iPhone 6/6+ 中的 UI 元素模糊

mysql - 如何从表中删除外键?

sql - 澄清为什么我们在查询 "expected to retrieve less 2 - 4% of rows in the table"时应该使用 SQL 索引?