mysql表上的正确索引

mysql表上的正确索引,mysql,sql,Mysql,Sql,当我在一个有2200万行的表上运行以下查询时,运行它需要20秒: select p.*, (select avg(close) from endOfDayData p2 where p2.symbol = p.symbol and p2.date between p.date - interval 6 day and p.date ) as MvgAvg_X from endOfDayData p where p.symbol = 'AAPL' 表结构如下所示: mysql> desc

当我在一个有2200万行的表上运行以下查询时,运行它需要20秒:

select p.*,
(select avg(close)
from endOfDayData p2
where p2.symbol = p.symbol and
p2.date between p.date - interval 6 day and p.date
) as MvgAvg_X
from endOfDayData p
where p.symbol = 'AAPL'
表结构如下所示:

mysql> desc endOfDayData;
+--------+---------------+------+-----+---------+-------+
| Field  | Type          | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| date   | date          | NO   | PRI | NULL    |       |
| symbol | varchar(14)   | NO   | PRI | NULL    |       |
| open   | decimal(10,4) | NO   |     | NULL    |       |
| high   | decimal(10,4) | NO   |     | NULL    |       |
| low    | decimal(10,4) | NO   |     | NULL    |       |
| close  | decimal(10,4) | NO   |     | NULL    |       |
| volume | int(11)       | NO   |     | NULL    |       |
+--------+---------------+------+-----+---------+-------+
并且存在以下索引:

mysql> show index from endOfDayData;
+--------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table        | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| endOfDayData |          0 | PRIMARY    |            1 | date        | A         |      162294 |     NULL | NULL   |      | BTREE      |         |               |
| endOfDayData |          0 | PRIMARY    |            2 | symbol      | A         |    24019617 |     NULL | NULL   |      | BTREE      |         |               |
| endOfDayData |          1 | EOD_dates  |            1 | date        | A         |       50145 |     NULL | NULL   |      | BTREE      |         |               |
| endOfDayData |          1 | EOD_symbol |            1 | symbol      | A         |       14322 |     NULL | NULL   |      | BTREE      |         |               |
+--------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (0.00 sec)
该机器是一个具有80GB ram和双处理器的专用机箱。我觉得它应该在一秒钟内运行,并具有正确的索引。谢谢

| id | select_type        | table | type | possible_keys                | key        | key_len | ref                | rows | Extra                 |  
+----+--------------------+-------+------+------------------------------+-------‌​-----+---------+--------------------+------+-----------------------+
|  1 | PRIMARY            | p     | ref  | EOD_symbol                   | EOD_symbol | 16      | const              | 8409 | Using index condition |  
|  2 | DEPENDENT SUBQUERY | p2    | ref  | PRIMARY,EOD_dates,EOD_symbol | EOD_symbol | 16      | financial.p.symbol | 1677 | Using index condition |
我已经创建了一个以ID int作为主键的新表,并在符号date上创建了一个索引

CREATE INDEX EODDateSym ON endOfDayData_new (symbol, date) USING BTREE;
还有17秒。再次感谢所有的想法和帮助

我的.conf是

[mysql]

# CLIENT #
port                           = 3306
socket                         = /var/lib/mysql/mysql.sock

[mysqld]

# GENERAL #
user                           = mysql
default-storage-engine         = InnoDB
socket                         = /var/lib/mysql/mysql.sock
pid-file                       = /var/lib/mysql/mysql.pid

# MyISAM #
key-buffer-size                = 32M
myisam-recover                 = FORCE,BACKUP

# SAFETY #
max-allowed-packet             = 16M
max-connect-errors             = 1000000

# DATA STORAGE #
datadir                        = /var/lib/mysql/

# BINARY LOGGING #
log-bin                        = /var/lib/mysql/mysql-bin
expire-logs-days               = 14
sync-binlog                    = 1
server_id              = 1

# CACHES AND LIMITS #
tmp-table-size                 = 32M
max-heap-table-size            = 32M
query-cache-type               = 0
query-cache-size               = 0
max-connections                = 500
thread-cache-size              = 50
open-files-limit               = 65535
table-definition-cache         = 4096
table-open-cache               = 4096

# INNODB #
innodb-flush-method            = O_DIRECT
innodb-log-files-in-group      = 2
innodb-log-file-size           = 512M
innodb-flush-log-at-trx-commit = 1
innodb-file-per-table          = 1
innodb-buffer-pool-size        = 68G

# LOGGING #
log-error                      = /var/lib/mysql/mysql-error.log
log-queries-not-using-indexes  = 1
slow-query-log                 = 1
slow-query-log-file            = /var/lib/mysql/mysql-slow.log

由于您同时在
符号
日期
上进行匹配,因此需要在这两列上设置索引,
(符号,日期)
,以便它在您所表达的条件下有效

MySQL通常为给定表的作业选择最佳索引,不能以任何有意义的方式将两者结合起来


如果您将这两个都作为主键,这是非常奇怪的,可能会损害性能。
UNIQUE
索引最好使用常规的
INT自动递增主键
ID类型列。当主键尽可能紧凑时,MySQL的性能最好。

列表中的第三个索引(
EOD_Date
)几乎一文不值。你应该放下它。真的
Date
已经是主键中的第一个字段,因此主键几乎总是(如果不是总是)在该索引上被选择。保留该索引实际上会使系统变慢,因为MySql仍将负责维护该索引

您需要的是更新您的
EOD_符号
索引,以便它还包括日期字段作为索引中的第二列。您可能还希望
close
字段作为索引中的第三列。这意味着该索引覆盖了主键,并且通过
close
字段,它还完全覆盖了相关的子查询(内部select语句):

确保此索引替换现有的EOD_符号索引。一旦这个索引准备好了,MySql很少会使用这个索引而不是这个索引,而且MySql需要做大量的工作来维护这两个索引,特别是在插入和更新时

通过使用主键的
符号、日期
顺序,您可以获得更好的查询性能,但这可能会对其他查询产生负面影响,或者更糟糕地影响插入性能

最后,我经常看到人们看到一个使用列的查询,并认为他们可以通过为该特定列添加索引来加快查询速度。索引不是这样工作的。当列上的索引符合查询访问字段的顺序时,它会有所帮助。在这里,您的相关子查询首先需要按符号限制记录,然后在符号内按日期限制使用哪些记录,因此您需要一个使用这两列并按顺序的查询



我刚刚看到了MySql配置的编辑。我会尝试增加
tmp表大小
最大堆表大小
。这不仅适用于临时表,还适用于运行查询的工作集所在的位置。如果它们太小,MySql将不得不将活动查询的数据放在磁盘上。

我可以想象查询计划是按日期进行范围扫描,然后按符号进行匹配。要扫描的范围相当大,它是根据外部选择的符号来完成的

我会尝试创建一个索引,将
(符号,日期)
作为列。由于符号可能比日期少得多,所以按符号扫描范围然后按日期过滤可能会更快,甚至可能在外部查询和内部查询之间的哈希连接期间完成


但是,在进行任何操作之前,您必须实际运行
解释
,并且可能需要
分析表

您是否可以发布
显示创建表endOfDayData
的结果,而不是
DESC
版本?子查询返回了多少行?从endOfDayData p2中选择avg(关闭),其中p2.symbol=p.symbol和p2.date介于p.date-间隔6天和p.date之间使用
EXPLAIN select…
,查看正在使用哪些索引,以及应该创建哪些索引来帮助此查询。@user3546638下面有一个指向您的问题的编辑链接。使用该选项可添加此类信息。
endOfDayData
中有多少行具有symbol
AAPL
?没有设置
symbol
date
,因为主键已经为您提供了该索引?请按“否”,因为它们的顺序不正确。当前主键在日期第一和符号第二处索引。这和先按符号索引,再按日期索引是不同的。谢谢。刚刚使用BTREE在endOfDayData(符号,日期)上创建了一个新索引
CREATE index EODDateSymCREATE INDEX EOD_DateSymClose ON endOfDayData (symbol, date, close) USING BTREE;