sql查询很慢

Posted

技术标签:

【中文标题】sql查询很慢【英文标题】:sql query is slow 【发布时间】:2011-11-18 19:22:48 【问题描述】:

我有一个 phpmyadmin 数据库,其中包含 1 000 000 条记录,我需要在其中搜索。每周都会添加 500 000 条记录。

所以,这就是我需要的:

location_id value   date        time        name                lat     lng
3            234    2011-11-18  19:50:00    Amerongen beneden   5.40453 51.97486
4            594    2011-11-18  19:50:00    Amerongen boven     5.41194 51.97507

我用这个查询来做这个:

SELECT location_id, value, date, time, locations.name, locations.lat, locations.lng FROM
(
SELECT location_id, value, date, time from `measurements` 
LEFT JOIN units ON (units.id = measurements.unit_id)
WHERE units.name='Waterhoogte'
ORDER BY measurements.date DESC, measurements.time DESC
) as last_record
LEFT JOIN locations on (locations.id = location_id)
GROUP BY location_id

这需要 30 秒。我该如何改进呢?这是我的结构:

CREATE TABLE IF NOT EXISTS `locations` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `code` varchar(255) NOT NULL,
  `lat` varchar(10) NOT NULL,
  `lng` varchar(10) NOT NULL,
  `owner_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=244 ;

-- --------------------------------------------------------

--
-- Table structure for table `measurements`  
--

CREATE TABLE IF NOT EXISTS `measurements` (
  `id` int(11) NOT NULL auto_increment,
  `date` date NOT NULL,
  `time` time NOT NULL,
  `value` varchar(255) NOT NULL,
  `location_id` int(11) NOT NULL,
  `unit_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=676801 ;

-- --------------------------------------------------------

--
-- Table structure for table `owner`
--

CREATE TABLE IF NOT EXISTS `owner` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

-- --------------------------------------------------------

--
-- Table structure for table `units`
--

CREATE TABLE IF NOT EXISTS `units` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `description` text NOT NULL,
  `unit_short` varchar(255) NOT NULL,
  `owner_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=44 ;

phpmyadmin 可以处理的限制是多少?

【问题讨论】:

我想澄清这不是 phpmyadmin 的限制。这是 mysql 运行查询的速度。 注意:phpmyadmin 不是数据库。它是一个基于 PHP 的 INTERFACE 到 mysql 数据库服务器。 【参考方案1】:

在units.name 上创建索引是一个好的开始。 您还应该真正重新考虑要撤回的数据量。 真的有人会筛选那么多记录吗?更改您的查询以限制记录数并考虑涉及分页机制的 UI 界面。

【讨论】:

我将 WHERE units.name='Waterhoogte' 替换为:WHERE units.id=4,将其缩短到 2 秒。还有其他方法可以更好地重写此查询吗? 你有这个字段的索引吗?您可能还希望在 location.id 上有一个索引。最终,您可以做更多的事情来使您的查询“更快”。更多的是您将多少记录带​​回客户的问题。限制它并编写一些漂亮的 UI,在需要时触发更多记录。带回这么多记录是不行的。当您进行 google 搜索并返回 40 页结果时,大多数情况下您只关心前 2 页,甚至是第二页。 好的,谢谢大家! : 显示第 0 - 29 行(总共 30 行,查询耗时 1.4580 秒),我可以忍受这个 @Melvin - 对我来说这相当快。【参考方案2】:

您需要在units.name 上放置一个索引或唯一索引。

【讨论】:

【参考方案3】:

添加以下索引:

unit.name 和 unit.id 上的复合索引(覆盖索引)。 测量.日期和测量.时间的复合索引。 location.id 上的索引

【讨论】:

【参考方案4】:

您应该首先尝试在units.name 上创建索引。但要明白,索引是有折衷的——读操作会更快,但它会减慢写操作的速度。如果您对此感到担忧,或者您受到写入缓慢的影响,那么您可能需要尝试在units.name 中使用较少数量的字符创建索引。

例如,要在 units.name 的前 12 个字符上声明索引,您需要声明以下内容:

CREATE INDEX first_twelve ON units (name(12));

同样,如果您没有注意到仅添加索引会产生任何不良影响,则可能没有必要这样做,但请记住这一点。

【讨论】:

【参考方案5】:
SELECT measurements.location_id, measurements.value, measurements.date, measurements.time, locations.name, locations.lat, locations.lng
FROM measurements
LEFT JOIN units ON units.id = measurements.unit_id
LEFT JOIN locations ON locations.id = measurements.location_id
WHERE units.id = 4
GROUP BY measurements.location_id
ORDER BY measurements.date DESC, measurements.time DESC

【讨论】:

谢谢,它更快,但显示 ASC 的“测量”记录,我想要最新的记录。 order by 需要在 group by 之前发生。我无法弄清楚这是如何工作的。这个查询实际上是我首先提出的。 @Melvin 在 where 子句中有子查询可能会更快。 date = select max date。然后你可以摆脱你的分组和排序。将您的日期和时间放在一个日期时间字段中也会更快,但这是另一回事。

以上是关于sql查询很慢的主要内容,如果未能解决你的问题,请参考以下文章

DSL和SQL查询很慢

SQL 查询在 SQL Server CE 中很慢,但在 SQL Server 中很快

sql查询在Hibernate中很慢,在mysql上很快

打开多个查询时访问 SQL-Server 很慢

使用格式化日期函数时 SQL 查询运行速度很慢

Apache Airflow - 在 AWS MWAA 上解析 SQL 查询很慢