MySQL innoDB:查询执行时间过长

Posted

技术标签:

【中文标题】MySQL innoDB:查询执行时间过长【英文标题】:MySQL innoDB: Long time of query execution 【发布时间】:2013-05-10 11:17:20 【问题描述】:

我在运行此 SQL 时遇到问题:

我认为是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

【问题讨论】:

那么,您的问题是什么? 我需要改进该表,以便快速进行该查询,我不知道如何索引或索引什么,因为图片显示很多 null 并且它们不好。跨度> 【参考方案1】:

首先,在(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 的建议并将列拆分为datetime 列。

【讨论】:

那么,它有帮助吗?现在执行时间如何? 你编辑了它,但是第一版是在 0,005 秒内执行的,所以很神奇@ypercube 不知道为什么它这么快,因为我没有索引来尝试是否是问题,而且它运行得很好 =) 我的编辑没有改变代码。我只添加了 cmets 和最后一段。很高兴听到它现在运行得很快。【参考方案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

【讨论】:

【参考方案3】:

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

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 更改为非空值。空值和索引不是很合适。

【讨论】:

查询中有group by。所以子查询中没有一条记录 我需要您的帮助添加索引 =) 查看@ypercube 的答案,因为他提供了用于添加索引的表更改

以上是关于MySQL innoDB:查询执行时间过长的主要内容,如果未能解决你的问题,请参考以下文章

AWS RDS MySql 具有复合索引和日期范围的简单查询在大约 800 万个数据中执行时间过长

查询执行时间过长

SQL 查询执行时间过长。需要提高查询的性能

MongoDB 查询执行时间过长

小表上的简单 SQL 查询执行时间过长

oracle olap 查询执行时间过长