mysql表上的正确索引
当我在一个有2200万行的表上运行以下查询时,运行它需要20秒: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
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
中有多少行具有symbolAAPL
?没有设置symbol
和date
,因为主键已经为您提供了该索引?请按“否”,因为它们的顺序不正确。当前主键在日期第一和符号第二处索引。这和先按符号索引,再按日期索引是不同的。谢谢。刚刚使用BTREE在endOfDayData(符号,日期)上创建了一个新索引CREATE index EODDateSym当我再次运行时,仍然是17.75秒。我将尝试创建一个int自动插入并报告。再次感谢您的快速回复everyone@user3546638不要再创建另一个索引。(符号,日期)的新索引将完全取代现有的EOD_符号索引。你不需要也不想要两者。
CREATE INDEX EOD_DateSymClose ON endOfDayData (symbol, date, close) USING BTREE;