MySQL查询性能似乎与参数数量成线性关系?
我有这样的设置:MySQL查询性能似乎与参数数量成线性关系?,mysql,sql,Mysql,Sql,我有这样的设置: 使用mysql 5.5 建筑物有一套测量设备 测量值存储在测量值-表中 有多种不同的类型 用户可以访问整个建筑或一套设备 几百万次测量 表的创建如下所示: CREATE TABLE `measurements` ( `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `building_id` INT(10) UNSI
- 使用mysql 5.5
- 建筑物有一套测量设备
- 测量值存储在测量值-表中
- 有多种不同的类型
- 用户可以访问整个建筑或一套设备
- 几百万次测量
CREATE TABLE `measurements` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`building_id` INT(10) UNSIGNED NOT NULL,
`equipment_id` INT(10) UNSIGNED NOT NULL,
`state` ENUM('normal','high','low','alarm','error') NOT NULL DEFAULT 'normal',
`measurement_type` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `building_id` (`building_id`),
INDEX `equipment_id` (`equipment_id`),
INDEX `state` (`state`),
INDEX `timestamp` (`timestamp`),
INDEX `measurement_type` (`measurement_type`),
INDEX `building_timestamp_type` (`building_id`, `timestamp`, `measurement_type`),
INDEX `building_type_state` (`building_id`, `measurement_type`, `state`),
INDEX `equipment_type_state` (`equipment_id`, `type`, `state`),
INDEX `equipment_type_state_stamp` (`equipment_id`, `measurement_type`, `state`, `timestamp`),
) COLLATE='utf8_unicode_ci' ENGINE=InnoDB;
SELECT *
FROM `measurements`
WHERE
`measurements`.`state` IN ('high','low','alarm')
AND `measurements`.`equipment_id` IN (
SELECT `equipment_users`.`equipment_id`
FROM `equipment_users`
WHERE `equipment_users`.`user_id` = 1
)
AND (`measurements`.`measurement_type` IN ('temperature','luminosity','humidity'))
ORDER BY `measurements`.`timestamp` DESC
LIMIT 50
现在我需要查询用户可以访问的某些类型的最后50个度量值。如果用户可以访问整个建筑,那么查询将运行得非常非常快。但是,如果用户只能访问单独的设备,则查询执行时间似乎会随着设备ID的数量线性增长。例如,我测试了in查询中只有2个设备ID,执行时间大约为10毫秒。在130台设备上,花费了2.5秒。我使用的查询如下所示:
CREATE TABLE `measurements` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`building_id` INT(10) UNSIGNED NOT NULL,
`equipment_id` INT(10) UNSIGNED NOT NULL,
`state` ENUM('normal','high','low','alarm','error') NOT NULL DEFAULT 'normal',
`measurement_type` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `building_id` (`building_id`),
INDEX `equipment_id` (`equipment_id`),
INDEX `state` (`state`),
INDEX `timestamp` (`timestamp`),
INDEX `measurement_type` (`measurement_type`),
INDEX `building_timestamp_type` (`building_id`, `timestamp`, `measurement_type`),
INDEX `building_type_state` (`building_id`, `measurement_type`, `state`),
INDEX `equipment_type_state` (`equipment_id`, `type`, `state`),
INDEX `equipment_type_state_stamp` (`equipment_id`, `measurement_type`, `state`, `timestamp`),
) COLLATE='utf8_unicode_ci' ENGINE=InnoDB;
SELECT *
FROM `measurements`
WHERE
`measurements`.`state` IN ('high','low','alarm')
AND `measurements`.`equipment_id` IN (
SELECT `equipment_users`.`equipment_id`
FROM `equipment_users`
WHERE `equipment_users`.`user_id` = 1
)
AND (`measurements`.`measurement_type` IN ('temperature','luminosity','humidity'))
ORDER BY `measurements`.`timestamp` DESC
LIMIT 50
该查询似乎倾向于使用
测量类型
索引,该索引需要15秒,迫使它使用设备类型
状态标记索引将其降到列出的数字。不过,为什么执行时间会随着ID的数量线性增加,我可以做些什么来防止这种情况发生呢?一个用户通常可以访问多少个ID?130是一个现实的数字吗?另外:每个设备id
通常有多少行?理论上可以获得50次相同的设备id(例如,如果用户只能访问单个设备,他将获得其最后50次测量值)是否正确,以及在这种情况下的预期结果是否正确?用户可以访问的设备id数量差异很大,从几到几百,130只是我地面测试的中间数字。是的,如果用户只能访问单个设备,那么他只能从该设备获取测量值。这在很大程度上取决于您的实际数据,哪种方式最快,这就是为什么我需要一些数字,特别是用户通常可以访问的行数(没有限制)。如果您有1.000.000个设备ID,每个设备ID有10个测量值,并且用户可以访问10-100个设备ID,或者如果您有100个设备ID,每个设备ID有100.000个测量值,则情况非常不同。附带问题:您是否在(用户id、设备id)
上有索引?当您强制索引设备类型状态戳时是否会使用该索引?是的,这很有意义。我检查了一下,目前用户可以访问的设备ID的最大数量是400,但只有少数用户的数量超过100。大多数在20-50岁左右。设备ID总共可能有10万个。是的,这个索引存在并被使用。我也在(1,2,3,…)中使用进行了测试,但这似乎不会影响性能。对于您的情况,我也会尝试设备类型状态标记。但是你可能会从一个覆盖索引中获益:尝试选择设备\u id,状态来自…
,而不是选择*
。如果速度足够快,您应该将使用的所有其他列添加到索引中,和/或仅使用选择中实际需要的列。您也可以在另一个表上尝试索引(时间戳、设备id、测量类型、状态)
和索引(设备id、用户id)
(同样,使用测试,从中选择设备id、状态),对于某些用户(设备越多),速度可能更快,取决于您的数据。用户通常可以访问多少ID?130是一个现实的数字吗?另外:每个设备id
通常有多少行?理论上可以获得50次相同的设备id(例如,如果用户只能访问单个设备,他将获得其最后50次测量值)是否正确,以及在这种情况下的预期结果是否正确?用户可以访问的设备id数量差异很大,从几到几百,130只是我地面测试的中间数字。是的,如果用户只能访问单个设备,那么他只能从该设备获取测量值。这在很大程度上取决于您的实际数据,哪种方式最快,这就是为什么我需要一些数字,特别是用户通常可以访问的行数(没有限制)。如果您有1.000.000个设备ID,每个设备ID有10个测量值,并且用户可以访问10-100个设备ID,或者如果您有100个设备ID,每个设备ID有100.000个测量值,则情况非常不同。附带问题:您是否在(用户id、设备id)
上有索引?当您强制索引设备类型状态戳时是否会使用该索引?是的,这很有意义。我检查了一下,目前用户可以访问的设备ID的最大数量是400,但只有少数用户的数量超过100。大多数在20-50岁左右。设备ID总共可能有10万个。是的,这个索引存在并被使用。我也在(1,2,3,…)中使用进行了测试,但这似乎不会影响性能。对于您的情况,我也会尝试设备类型状态标记。但是你可能会从一个覆盖索引中获益:尝试选择设备\u id,状态来自…
,而不是选择*
。如果速度足够快,您应该将使用的所有其他列添加到索引中,和/或仅使用选择中实际需要的列。您也可以在另一个表上尝试索引(时间戳、设备id、测量类型、状态)
和索引(设备id、用户id)
(同样,使用测试,从中选择设备id、状态),根据您的数据,对于某些用户(设备更多)来说速度更快。