我有一个简单的表,有15列:
CREATE TABLE MYTABLE(
ID int(11) NOT NULL AUTO_INCREMENT,
SYMBOL varchar(100) NOT NULL,
DATE varchar(100) NOT NULL,
TIME varchar(100) NOT NULL,
NUMBER decimal(38,0) NOT NULL,
A float DEFAULT NULL,
B float DEFAULT NULL,
C float DEFAULT NULL,
D float DEFAULT NULL,
E decimal(38,0) DEFAULT NULL,
F float DEFAULT NULL,
G decimal(38,0) DEFAULT NULL,
H decimal(38,0) DEFAULT NULL,
I decimal(38,0) DEFAULT NULL,
J float DEFAULT NULL,
K float DEFAULT NULL,
L decimal(38,0) DEFAULT NULL,
M decimal(38,0) DEFAULT NULL,
MILLIS decimal(38,0) DEFAULT NULL,
PRIMARY KEY (ID)
KEY SYM (SYMBOL) USING HASH
) ENGINE=InnoDB AUTO_INCREMENT=10250241 DEFAULT CHARSET=latin1
它由符号索引(哈希索引)。这个数据表(6gb)中大约有10000000行。在workbench中查询此表时,对于以下简单查询:
select * from MYTABLE WHERE symbol = 'A' and date>= '2018-08-01' and
date<= '2018-08-09' and time>= '09:24:00' and time <= '15:24:00' order by
millis desc ;'
需要4-5秒。当对数据库的读写同时发生时,性能进一步降低。但这是一个实时数据库,要求从一个连接写入数据,从另一个连接读取数据。
有人能提出一些优化性能的方法吗。随着时间的推移,我已经尝试了btree索引,但性能进一步下降。
如前所述,在对查询运行explain之后,我得到了以下结果:
'Using index condition; Using where; Using filesort'
4条答案
按热度按时间iq3niunx1#
对于此查询:
你想要索引吗
mytable(symbol, date, time)
. 事实上time
只有一个副本,所以索引覆盖WHERE
条款。包括
millis
没有帮助,因为在order by
.ddarikpa2#
用desc在符号和millis上创建索引。
j7dteeu83#
DECIMAL(38,0)
需要17个字节。你真的需要那个数据类型吗(FLOAT
需要4分钟,DOUBLE
需要8分钟,BIGINT
(缩小6gb将有助于提高性能,尤其是在innodb_buffer_pool_size
是小的。)如果
millis
是毫秒,为什么是38位,不是3位?不管怎样,DATETIME(3)
提供数据+时间+毫秒,全部打包为7个字节。此外,你可以从而考虑到
INDEX(symbol, datetime)
帮助解决问题WHERE
. (这不能用当前代码完成。)在这9天中的每一天过滤到白天。如果这真的是你想要的,那么没有一个索引能很好地工作。检查
<=
--我理解日期的包容性,但我暂时质疑。或者
INDEX(symbol, date)
或者INDEX(symbol, time)
是有用的。没有比这更好的了(除非你能把日期和时间结合起来)。把这两个加起来。HASH
innodb中不存在索引;这个请求被悄悄地变成了BTREE
,这对于“点查询”和“范围查询”差不多好,而且非常好。在您的查询中,“复合”btree查询(见上一段)要好得多。请提供
EXPLAIN SELECT ...
所以我们可以进一步推断出发生了什么。一切都不是
ID
真的可以选择吗?考虑使用NOT NULL
.'Using index condition; Using where; Using filesort'
--“文件排序”是不可避免的;接受现实吧。”使用索引条件(又名“icp”)是好的。j8ag8udp4#
我会从使用
DATE()
以及TIME()
类型而不是varchar
(或一个)DATETIME()
)-或储存在integer
作为Unix Time
. 在内部,它们将比字符串更有效。例如,比较两个整数大约需要1个cpu周期。要比较字符串,一般来说,每个字符都必须在循环中进行比较(直到有差异为止),除非使用了特殊的优化。如果数据是unicode格式的,则必须对每个字符进行特殊查找。
整数也比日期/时间字符串表示法占用更少的空间(unix时间为4字节),并且长度不可变(即使日期的长度都相同,在内部它们也将被视为可变长度字符串,需要额外的“长度字段”)。
还可以按照其他地方的建议创建适当的索引。
您确定要(只)在下订单吗
millis
,或者这只是一个测试?对于上面的查询,忽略
millis
,理想情况下,记录将按以下顺序存储在磁盘上:symbol, datetime (millis?)
. 这样,要返回的记录将在磁盘上以块的形式紧密地放在一起。否则,它们可能分布在整个表中,需要许多磁盘查找和(块)读取来检索所有记录。