[英]Optimization Mysql Query Left Join
我們希望通過以下查詢將calibration_data的條目映射到校准數據。 但是在我看來這個查詢的持續時間太長了(> 24h)。
有可能進行任何優化嗎? 我們現在添加了根據需要測試更多索引,但它對持續時間沒有任何影響。
[編輯]
硬件不應該是最大的瓶頸
EXPLAIN結果
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+------------------------------------------------+
| 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_data:
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;
表校准_數據
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;
一次性任務? 那沒關系? 獲取此數據后,您是否會每天逐步更新“匯總表”?
收縮數據類型 - 龐大的數據需要更長的時間來處理。 示例:4字節的INT
DayOfMonth
可以是1字節的TINYINT UNSIGNED
。
您正在將TIMESTAMP
移動到DATETIME
。 這可能會或可能不會如您所願。
對於IPv4, INT UNSIGNED
可以正常使用,但您無法在其中使用IPv6。
COUNT(*)
可能不需要4字節的INT
; 看到較小的變種。
在適當的地方使用UNSIGNED
。
mac-address以你擁有的方式占用19個字節; 它可以很容易地轉換為6字節的BINARY(6)
。 參見REPLACE()
, UNHEX()
, HEX()
等。
innodb_buffer_pool_size
的設置是innodb_buffer_pool_size
? 你擁有的大RAM可能大約100G。
時間范圍重疊嗎? 如果沒有,請利用這一點。 另外,不要在PRIMARY KEY
包含不必要的列,例如EndTime
。
使GROUP BY
列的順序與knn_data的PRIMARY KEY
相同; 這樣可以避免在INSERT
期間發生大量的塊分裂。
最大的問題是在calibration_data
沒有有用的索引,因此JOIN
必須一次又一次地進行全表掃描! 3M排的2K掃描結果! 讓我關注這個問題......
沒有好辦法做WHERE x BETWEEN start AND end
因為MySQL不知道日期時間范圍是否重疊。 在這種情況下,沒有真正的解決辦法,所以讓我以不同的方式處理它......
開始和結束是“常規”嗎? 喜歡每個小時? 因此,我們可以做一些計算而不是 BETWEEN
。 如果是這種情況,請告訴我。 我會繼續思考。
對於“范圍”查詢來說,這是一個令人討厭且經典的問題:優化器不會使用您的索引並最終進行全表掃描。 在您的解釋計划中,您可以在列type=ALL
上看到此信息。
理想情況下,您應該在鍵列中具有type=range
和某些內容
一些想法:
我懷疑你改變你的聯合
ON m.visit BETWEEN cal.BeginTime AND cal.EndTime
至
ON m.visit >= cal.BeginTime AND m.visit <= cal.EndTime
會工作,但仍然試一試。
在兩個表上觸發ANALYSE TABLE
。 這將更新表上的統計信息,可能有助於優化器做出正確的決策(即使用索引)
將查詢更改為此可能也有助於強制優化器使用索引:
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;
這就是我所想的一切......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.