Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL查询性能似乎与参数数量成线性关系?_Mysql_Sql - Fatal编程技术网

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、状态),根据您的数据,对于某些用户(设备更多)来说速度更快。