MySQL查询性能与并发读写

时间:2018-08-10 05:31:30

标签: mysql sql database mysql-workbench query-performance

我有一个简单的表,有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)的数据中大约有10,000,000行。当我在工作台中查询此表时,进行诸如:

的简单查询
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索引,但是性能进一步降低了。

根据建议,对查询运行解释后,得到以下结果:

'Using index condition; Using where; Using filesort'

Explain result

4 个答案:

答案 0 :(得分:2)

DATE varchar(100) NOT NULL,
TIME varchar(100) NOT NULL,

我将从使用DATE()TIME()类型而不是varchar(或一个DATETIME())开始-或将它们存储为{{1 }}。在内部,它们将比字符串更有效。

例如,比较两个整数大约需要1个CPU周期。通常,要比较字符串,必须使用循环比较每个字符(直到有区别),除非使用特殊的优化。如果数据采用unicode,则必须对每个字符进行特殊查找。

整数还比日期/时间字符串表示占用更少的空间(Unix时间为4字节),并且长度也不可变(即使日期长度相同,在内部也将它们视为可变长度字符串,需要一个额外的“长度字段”)。

还要按照其他地方的建议创建适当的索引。

integer

您确定要(仅)按Unix Time进行订购,还是仅作为测试?

对于上述查询,忽略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 ; 上的单独排序,理想情况下,记录将按以下顺序存储在磁盘上:millis。这样,要返回的记录将在磁盘上的块中紧密靠近。否则,它们可能会散布在整个表上,需要进行许多磁盘搜索和(块)读取才能获取所有记录。

答案 1 :(得分:0)

使用desc在符号和毫秒上创建索引。

答案 2 :(得分:0)

对于此查询:

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 ;

您要在mytable(symbol, date, time)上建立索引。实际上,time仅作为副本存在,因此索引覆盖了WHERE子句。

包含millis并没有帮助,因为在order by之前需要进行过滤。

答案 3 :(得分:0)

DECIMAL(38,0)占用17个字节。您是否真的需要该数据类型? ({FLOAT占4,DOUBLE占8,BIGINT占8。)(缩小6GB将有助于提高性能,尤其是在innodb_buffer_pool_size很小的情况下。)

如果millis是毫秒,为什么是38位而不是3位?无论如何,DATETIME(3)提供了一个数据+时间+毫秒,它们全部包装成大约7个字节。此外,您可以

ORDER BY datetime

,从而允许有效的INDEX(symbol, datetime)帮助WHERE。 (这不能用您当前的代码来完成。)

  date >= '2018-08-01' and date <= '2018-08-09' and 
  time >= '09:24:00' and time <= '15:24:00'

在这9天内的每一天都过滤为白天。如果这确实是您想要的,那么没有索引能很好地工作。检查<=的使用-我了解日期的包容性,但我对此有疑问。

INDEX(symbol, date)INDEX(symbol, time)都很有用。没有别的更好(除非您可以结合使用日期和时间)。将两者都添加。

HASH索引在InnoDB中不存在;该请求被默默地转换为BTREE,这与“点查询”一样好,而对于“范围查询”则好得多。在您的查询中,“复合” BTree查询(请参见上一段)要好得多。

请提供EXPLAIN SELECT ...,以便我们进一步推断正在发生的事情。

ID以外的其他内容是否都是可选的?考虑使用NOT NULL

'Using index condition; Using where; Using filesort'-不可避免的是“文件排序”;忍受它。 “使用索引条件”(又称“ ICP”)是好的。