我在使用此查询时遇到了一些问题,每当我使用它时,cpu的使用率从5%增加到67%-100%。
我正在通过java服务在ubuntu中运行mysql服务器,但即使我通过任何mysql ide执行查询,结果都是一样的。
我已在网上搜索过一些关于它的内容,所以我发布了mysql的配置文件。我添加了一些属性,然后我在一些帖子中发现但我认为我只是让它变得更糟。
嗯,这是我的my.cnf文件:
[mysqld]
innodb_file_per_table=1
innodb_buffer_pool_size = 256M
wait_timeout = 1800
local-infile=0
open_files_limit=10192
query_cache_size=128M
join_buffer_size=128K
thread_cache_size=4
table_cache=64
key_buffer_size=128M
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 1336
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
bind-address = 0.0.0.0
key_buffer = 2014M
max_allowed_packet = 2014M
thread_stack = 512K
thread_cache_size = 1024
myisam-recover = BACKUP
max_connections = 200
query_cache_limit = 2048M
log_error = /var/log/mysql/error.log
expire_logs_days = 10
max_binlog_size = 100M
[mysqldump]
quick
quote-names
max_allowed_packet = 16M
[mysql]
[isamchk]
key_buffer = 16M
!includedir /etc/mysql/conf.d/
我正在使用此查询:
select regPosition.deviceId, count(regPosition.speed), max(regPosition.speed) from regPosition where (TIMESTAMPDIFF(MINUTE, lastPositionTime,now()) <= '5') and regPosition.speed >= '10' group by regPosition.deviceId;
表的类型是Myisam,它有大约2M的注册表,并且idPosition作为索引。 这是创建表查询:
CREATE TABLE `regPosition` (
`idPosition` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Id autoincremental.',
`deviceId` int(5) NOT NULL COMMENT 'Id numérico del equipo. Identificador único para cada vehículo.',
`lastPositionTime` datetime NOT NULL COMMENT 'Fecha/hora en que se registra la marca de posición (realizada por el dvr).',
`divisionew` varchar(2) DEFAULT NULL COMMENT 'Orientación Este u Oeste.',
`longitude` int(11) NOT NULL COMMENT 'longitud.',
`divisionns` varchar(2) DEFAULT NULL COMMENT 'Orientación Norte o Sur.',
`latitude` int(11) NOT NULL COMMENT 'Latitud.',
`direction` int(11) DEFAULT NULL COMMENT 'Dirección en que apunta el dispositivo.',
`gradeLon` varchar(100) DEFAULT NULL COMMENT 'Longitud transformada a grados (en decimal).',
`gradeLat` varchar(100) DEFAULT NULL COMMENT 'Latitud transformada a grados (en decimal).',
`speed` int(11) NOT NULL COMMENT 'Velocidad del vehículo. Registrada por el dvr',
PRIMARY KEY (`idPosition`),
KEY `index` (`idPosition`) USING HASH
) ENGINE=MyISAM AUTO_INCREMENT=6562682 DEFAULT CHARSET=latin1;
[编辑]
查询的目的是获取设备的id和速度大于10的次数(这只是一个例子,它可能更多)并获得数据库记录的最大速度。
这个想法如下:如果速度在5分钟内超过60kmh 5次,我需要知道设备的id,最大速度和超过速度限制的次数。
如果你能给我任何帮助,我会非常高兴:)。
感谢您的帮助。
答案 0 :(得分:1)
添加索引:
... ON (deviceId, lastPositionTime, speed)
并更改查询。替换此谓词:
TIMESTAMPDIFF(MINUTE, lastPositionTime,now()) <= '5'
用这个:
lastPositionTime >= NOW() + INTERVAL -5 MINUTE
这将为您提供查询的覆盖索引(EXPLAIN将显示“使用索引”),这意味着可以从索引中满足查询。
首先需要deviceId
列,因为MySQL可以使用以该列作为前导列的索引来优化GROUP BY操作(避免排序操作)。
您希望裸lastPositionTime
列上有谓词,因此MySQL可以进行索引范围扫描。当该列被隐藏在函数内部时(例如TIMESTAMPDIFF),MySQL必须为每一行评估该函数。索引范围扫描更快,因为它可以消除对很多行的功能评估。
由于speed
列上还有一个谓词,因此您也希望在索引中使用该谓词。
没有引用其他列,因此可以完全从索引中满足查询,而无需访问基础表中的页面。
答案 1 :(得分:1)
这是我的方法,它应该通过表ONCE,没有使用MySQL变量的连接。我在这里申请的前提如下。有序结果必须是设备ID和报告时间的结果。 MySQL变量将跟踪......我是否在同一台设备上工作?和,是最后一条记录启动设备的5分钟内的当前记录,或上次超过给定速度限制的记录这就是原因。假设我有一个给定的设备在15分钟内报告,从早上8点开始报告,并且为了简单的目的每分钟报告一次。速度如下:
8:00 58 -- Start group 8:00, set max time to still consider as 8:05
8:01 60 -- speeding... within the 8:00-8:05 range. NEW end 5 minutes from now 8:06
8:02 58 -- not speeding
8:03 58 -- not speeding
8:04 59 -- not speeding
8:05 58 -- not speeding
8:06 59 -- not speeding... end of the 8:06 range, 1 over limit, ignore this
8:07 60 -- NEW cycle for device, start at 8:07 set ending time to 8:12 -- SPEEDING 1
8:08 61 -- STILL speeding max 61, extend ending time from 8:08 + 5 minutes to 8:13
8:09 62 -- STILL speeding max 62, extend ending time from 8:09 + 5 minutes to 8:14
8:10 59 -- not speeding
8:11 59 -- not speeding
8:12 60 -- SPEEDING AGAIN, within the 8:14 cutoff... reset 5 minutes from now 8:17
8:13 62 -- speeding still, extend to 8:18
8:14 64 -- speeding still, new max 64 and extend to 8:19
8:15 62 -- still speeding... total times 7 with max of 64 (so far)
如果不考虑上述格式,则必须计算
中的所有记录8:00 to 8:05
8:01 to 8:06
8:02 to 8:07, etc.
对于样本数据,您可以从
加速8:05 to 8:09
8:06 to 8:10
8:07 to 8:11, etc
但是这种方式一直在观察从最后一个加速时间开始的5分钟滚动截止时间。例如,如果在8:20-8:26之间,该人减少到少于60,那么在下次遇到超速时将开始新的循环。否则,请考虑如果一个人从8:00到10:00超速,将返回多少条记录。如果报告是每分钟1次,您将有2 * 60条记录...如果报告更频繁,则会显示更多。
随着设备ID的变化,“第一时间”识别出下一个加速考虑周期的开始。处理完每条记录后,将该设备ID放入“@lastDevice”变量中,以进行下一个循环比较。如果在当前记录上没有遇到超速,则@nextTimeCutoff将与前一行相同,或者无论设备是否为ADD 5 MINUTES ...如果设备正在改变,因为它是条目的最后一行,下一行将开始无论如何,新的“LimitSequence”增加1。
现在,所有这一切,这个查询将为您简化项目。如果你知道你所担心的速度限制(60kph),我的内部查询只会预先知道那些设备被标记为超速的记录。如果你有2M的记录要通过,而且其中大部分都没有超速,那么为什么甚至可以和他们一起玩。因此,内部查询仅限于那些正在加速并将它们放入mysql变量处理的正确顺序的查询。如上所述,它将处理人员第一次超速时的滚动时间段。
select
r1.DeviceID,
@overLimitSeq := if( r1.DeviceID = @lastDevice
AND r1.lastPositionTime <= @nextTimeCutoff,
@overLimitSeq, @overLimitSeq +1 ) as LimitSequence,
min( r1.lastPositionTime ) as SpeedingTimeStart,
max( r1.lastPositionTime ) as SpeedingTimeEnd,
max( r1.speed ) as MaxSpeed,
count(*) as TimesOverLimit,
@lastDevice := r1.DeviceID as CompareForNextID,
@nextTimeCutoff := r1.lastPositionTime + interval 5 minute as NextCutoff
from
( select rp.deviceID,
rp.lastPositionTime,
rp.speed
from
regPosition rp
where
rp.speed >= 60
order by
rp.deviceID,
rp.lastPositionTime ) r1,
( select @lastDevice := 0,
@overLimitSeq := 0,
@nextTimeCutoff := now() ) sqlvars
group by
r1.DeviceID,
LimitSequence
having
TimesOverLimit > 2
order by
r1.deviceID,
r1.lastPositionTime
答案 2 :(得分:1)
我实际上发现了高CPU使用率的问题。
问题是表的使用不良索引,基本上是我创建索引时定义的顺序。
当我使用&#34;解释&#34;在查询中我得到的搜索是在数百万个注册表中完成的,即使使用直接过滤器(即使它发生了限制100)。
原因是索引,所以我重新确定了索引的顺序,这样解释显示搜索在不到400个注册表中完成,并且cpu使用情况非常完美。
例如这个sql:
EXPLAIN
SELECT d.deviceId, r.divisionew
FROM
device d, regPosition r
WHERE
d.enabled = 1
AND d.deviceId = r.deviceId
AND (DATE_SUB(now(),INTERVAL 8 MINUTE)) < r.lastPositionTime
ORDER BY d.deviceId DESC
这个是在不使用索引的情况下进行搜索,因此查询完成了大约8百万个注册表的搜索。
通过重新分配索引并且订单正确,此查询在少于400行中搜索完成。
所以基本上改变了索引的顺序,我可以得到索引的工作,以及高cpu使用率的消失。
我只是改变了索引的顺序。我之前有过deviceId,lastPositionTime和更多。 按照这个顺序,索引在改变之后没有工作,添加了分区,改变了顺序并删除了无用的参数,索引就像魅力一样。
因此,当您遇到一些使用mysql的高CPU使用率的麻烦时,您应该检查索引顺序,因为如果您设计的索引应该能够加快查询的速度,并且如果它不存在则可能存在问题索引分配。
至少解决了我的问题。
谢谢大家的帮助。