优化Mysql查询左连接
我们希望通过以下查询将校准数据的条目映射到校准数据。但在我看来,这个查询的持续时间太长了(>24小时) 是否有可能进行优化? 我们现在根据需要增加了测试更多索引的功能,但这对持续时间没有任何影响 [编辑] 硬件不应该是最大的瓶颈优化Mysql查询左连接,mysql,performance,left-join,query-optimization,explain,Mysql,Performance,Left Join,Query Optimization,Explain,我们希望通过以下查询将校准数据的条目映射到校准数据。但在我看来,这个查询的持续时间太长了(>24小时) 是否有可能进行优化? 我们现在根据需要增加了测试更多索引的功能,但这对持续时间没有任何影响 [编辑] 硬件不应该是最大的瓶颈 128 GB内存 1TB SSD RAID 5 32芯 解释结果 +----+-------------+-------+------------+------+---------------+------+---------+------+---------+--
- 128 GB内存
- 1TB SSD RAID 5
- 32芯
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+------------------------------------------------+
| 1 | SIMPLE | cal | NULL | ALL | NULL | NULL | NULL | NULL | 2009 | 100.00 | Using temporary; Using filesort |
| 1 | SIMPLE | m | NULL | ALL | visit | NULL | NULL | NULL | 3082466 | 100.00 | Range checked for each record (index map: 0x1) |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+------------------------------------------------+
需要太长时间的查询:
Insert into knn_data (SELECT cal.X AS X,
cal.Y AS Y,
cal.BeginTime AS BeginTime,
cal.EndTime AS EndTime,
avg(m.dbm_ant) AS avg_dbm_ant,
m.ant_id AS ant_id,
avg(m.location) avg_location,
count(*) AS count,
m.visit
FROM calibration cal
LEFT join calibration_data m
ON m.visit BETWEEN cal.BeginTime AND cal.EndTime
GROUP BY cal.X,
cal.Y,
cal.BeginTime,
cal. BeaconId,
m.ant_id,
m.macHash,
m.visit;
表knn_数据:
CREATE TABLE `knn_data` (
`X` int(11) NOT NULL,
`Y` int(11) NOT NULL,
`BeginTime` datetime NOT NULL,
`EndTIme` datetime NOT NULL,
`avg_dbm_ant` float DEFAULT NULL,
`ant_id` int(11) NOT NULL,
`avg_location` float DEFAULT NULL,
`count` int(11) DEFAULT NULL,
`visit` datetime NOT NULL,
PRIMARY KEY (`ant_id`,`visit`,`X`,`Y`,`BeginTime`,`EndTIme`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
表校准
BeaconId, X, Y, BeginTime, EndTime
41791, 1698, 3944, 2016-11-12 22:44:00, 2016-11-12 22:49:00
CREATE TABLE `calibration` (
`BeaconId` int(11) DEFAULT NULL,
`X` int(11) DEFAULT NULL,
`Y` int(11) DEFAULT NULL,
`BeginTime` datetime DEFAULT NULL,
`EndTime` datetime DEFAULT NULL,
KEY `x,y` (`X`,`Y`),
KEY `x` (`X`),
KEY `y` (`Y`),
KEY `BID` (`BeaconId`),
KEY `beginTime` (`BeginTime`),
KEY `x,y,beg,bid` (`X`,`Y`,`BeginTime`,`BeaconId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
表1校准数据
macHash, visit, dbm_ant, ant_id, mac, isRand, posX, posY, sources, ip, dayOfMonth, location, am, ar
'f5:dc:7d:73:2d:e9', '2016-11-12 22:44:00', '-87', '381', 'f5:dc:7d:73:2d:e9', NULL, NULL, NULL, NULL, NULL, '12', '18.077636300207715', 'inradius_41791', NULL
CREATE TABLE `calibration_data` (
`macHash` varchar(100) COLLATE utf8_bin NOT NULL,
`visit` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`dbm_ant` int(3) NOT NULL,
`ant_id` int(11) NOT NULL,
`mac` char(17) COLLATE utf8_bin DEFAULT NULL,
`isRand` tinyint(4) DEFAULT NULL,
`posX` double DEFAULT NULL,
`posY` double DEFAULT NULL,
`sources` int(2) DEFAULT NULL,
`ip` int(10) unsigned DEFAULT NULL,
`dayOfMonth` int(11) DEFAULT NULL,
`location` varchar(80) COLLATE utf8_bin DEFAULT NULL,
`am` varchar(300) COLLATE utf8_bin DEFAULT NULL,
`ar` varchar(300) COLLATE utf8_bin DEFAULT NULL,
KEY `visit` (`visit`),
KEY `macHash` (`macHash`),
KEY `ant, time` (`dbm_ant`,`visit`),
KEY `beacon` (`am`),
KEY `ant_id` (`ant_id`),
KEY `ant,mH,visit` (`ant_id`,`macHash`,`visit`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
在“范围”查询中,这是一个令人讨厌的经典问题:优化者不使用索引,最终会进行完整的表扫描。在您的解释计划中,您可以在列
type=ALL
上看到这一点
理想情况下,您应该在键列中包含type=range
和一些内容
一些想法:
我怀疑把你从
ON m.visit BETWEEN cal.BeginTime AND cal.EndTime
到
这就是我所想的……在“范围”查询中,这是一个令人讨厌的经典问题:优化者不使用您的索引,最终会进行完整的表扫描。在您的解释计划中,您可以在列
type=ALL
上看到这一点
理想情况下,您应该在键列中包含type=range
和一些内容
一些想法:
我怀疑把你从
ON m.visit BETWEEN cal.BeginTime AND cal.EndTime
到
这就是我想做的一切…一次性任务?那没关系吧?加载此数据后,是否每天递增更新“汇总表” 收缩数据类型——庞大的数据需要更长的处理时间。示例:4字节的
INT
DayOfMonth
可以是1字节的TINYINT无符号的
您正在将时间戳
移动到日期时间
。这可能会也可能不会像您预期的那样起作用
INT UNSIGNED
适用于IPv4,但不能将IPv6安装在其中
COUNT(*)
可能不需要4字节的INT
;请参阅较小的变体
在适当的情况下使用未签名的
一个mac地址需要19个字节;它可以很容易地转换成6字节的二进制(6)
。请参见REPLACE()
,UNHEX()
,HEX()
等
innodb缓冲池大小的设置是什么?对于你的大公羊来说可能是100克左右
时间范围重叠吗?如果没有,那就好好利用。另外,不要在主键中包含不必要的列,例如EndTime
按与knn_数据的主键相同的顺序排列GROUP BY
列;这将避免在插入过程中出现大量块拆分
最大的问题是,calibration\u data
中没有有用的索引,因此,JOIN
必须一次又一次地进行全表扫描!一个扩展的2K扫描3M行!让我把重点放在这个问题上
因为MySQL不知道日期时间范围是否重叠,所以在开始和结束之间没有很好的方法。在这种情况下没有真正的治疗方法,所以让我换一种方式来处理它
开始和结束是“常规”的吗?像每小时一样?当然,我们可以做一些计算,而不是在
之间进行。如果是这样,请告诉我;我会继续我的想法。一次性任务?那没关系吧?加载此数据后,是否每天递增更新“汇总表”
收缩数据类型——庞大的数据需要更长的处理时间。示例:4字节的INT
DayOfMonth
可以是1字节的TINYINT无符号的
您正在将时间戳
移动到日期时间
。这可能会也可能不会像您预期的那样起作用
INT UNSIGNED
适用于IPv4,但不能将IPv6安装在其中
COUNT(*)
可能不需要4字节的INT
;请参阅较小的变体
在适当的情况下使用未签名的
一个mac地址需要19个字节;它可以很容易地转换成6字节的二进制(6)
。请参见REPLACE()
,UNHEX()
,HEX()
等
innodb缓冲池大小的设置是什么?对于你的大公羊来说可能是100克左右
时间范围重叠吗?如果没有,那就好好利用。另外,不要在主键中包含不必要的列,例如EndTime
按与knn_数据的主键相同的顺序排列GROUP BY
列;这将避免在插入过程中出现大量块拆分
最大的问题是,calibration\u data
中没有有用的索引,因此,JOIN
必须一次又一次地进行全表扫描!一个扩展的2K扫描3M行!让我把重点放在这个问题上
因为MySQL不知道日期时间范围是否重叠,所以在开始和结束之间没有很好的方法。在这种情况下没有真正的治疗方法,所以让我换一种方式来处理它
开始和结束是“常规”的吗?像每小时一样?当然,我们可以做一些计算,而不是在
之间进行。如果是这样,请告诉我;我会继续我的想法。谢谢!!使用on和where条件尝试您的解决方案!解释显示了11.11的过滤值,因此值得测试。
之间的与=
等相同。注意一个潜在的错误:两个公式都包含在内,因此边界处的项目可能包含在两个不同的桶中!对
上的
设置为否。由于限制较少,它将扫描额外的行。@RickJames目的是让它使用索引而不是扫描更少的行。。。谢谢你的回答自从这个答案被接受以来,它真的有帮助吗?很多
Insert into knn_data (SELECT cal.X AS X,
cal.Y AS Y,
cal.BeginTime AS BeginTime,
cal.EndTime AS EndTime,
avg(m.dbm_ant) AS avg_dbm_ant,
m.ant_id AS ant_id,
avg(m.location) avg_location,
count(*) AS count,
m.visit
FROM calibration cal
LEFT join calibration_data m
ON m.visit >= cal.BeginTime
WHERE m.visit <= cal.EndTime
GROUP BY cal.X,
cal.Y,
cal.BeginTime,
cal. BeaconId,
m.ant_id,
m.macHash,
m.visit;