MySQL innoDB:查询执行时间长

时间:2013-05-10 11:17:20

标签: mysql sql query-optimization innodb

我遇到运行此SQL的麻烦:

enter image description here

我认为这是一个index problem,但我不知道,因为我不建立这个数据库而且我只是一个简单的程序员。

问题是,该表有64260条记录,因此查询在执行时会变得疯狂,我必须停止mysql并再次运行,因为计算机被冻结了。

感谢。

编辑:表架构

CREATE TABLE IF NOT EXISTS `value_magnitudes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` float DEFAULT NULL,
  `magnitude_id` int(11) DEFAULT NULL,
  `sdi_belongs_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `reading_date` datetime DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1118402 ;

查询

select * from value_magnitudes
where id in 
(
    SELECT min(id)
    FROM value_magnitudes
    WHERE magnitude_id = 234
    and date(reading_date) >= '2013-04-01'
    group by date(reading_date)
)

EDIT2

enter image description here

3 个答案:

答案 0 :(得分:2)

由于您希望每天获得结果,因此需要使用函数date()从日期时间列中提取日期。这使得索引无用。

您可以将reading_date列拆分为reading_datereading_time。然后,您可以在没有函数的情况下运行查询,索引将起作用。

此外,您可以将查询更改为join

select * 
from value_magnitudes v
inner join 
(
    SELECT min(id) as id
    FROM value_magnitudes
    WHERE magnitude_id = 234
    and reading_date >= '2013-04-01'
    group by reading_date
) x on x.id = v.id

答案 1 :(得分:2)

首先,在(magnitude_id, reading_date)上添加索引:

ALTER TABLE
  ADD INDEX magnitude_id__reading_date__IX       -- just a name for the index
    (magnitude_id, reading_date) ;

然后尝试这种变化:

SELECT vm.* 
FROM value_magnitudes AS vm
  JOIN 
  ( SELECT MIN(id) AS id
    FROM value_magnitudes
    WHERE magnitude_id = 234
      AND reading_date >= '2013-04-01'         -- changed so index is used
    GROUP BY DATE(reading_date)
  ) AS vi
    ON vi.id = vm.id ;

GROUP BY DATE(reading_date)仍然需要将该函数应用于所有选定的(索引)行并且无法改进,除非您按照@ jurgen的建议将列拆分为date和{ {1}}列。

答案 2 :(得分:1)

对于初学者,我会将您的查询更改为:

select * from value_magnitudes where id = (
  select min(id) from value_magnitudes
  where magnitude_id = 234
  and DATE(reading_date) >= '2013-04-01' 
)

当子查询只返回一条记录时,您不需要使用IN子句。

然后,我会确保你在magnitude_id和reading_date(可能是两个字段索引)上有一个索引,就像你在子查询中查询的一样。没有该索引,您每次都在扫描表。

如果可能的话,将magnitude_id和reading_date更改为非null。空值和索引不是很合适。