子查询和大表。如何提高速度?

时间:2017-07-28 12:35:17

标签: mysql join subquery query-optimization

我对MySQL并不陌生,但我绝对会想到这一点。

我想根据日期和大气水平显示巴拿马和伯利兹的气温差异表。该查询应该根据日期和大气水平匹配巴拿马和伯利兹数据,并返回前30个差异,按差异程度排序。

然而,它非常缓慢(超过30秒)所以它超时了。我为这个数据集编写的其他一些查询也非常慢(大约26s)。但是,如果我只运行子查询,它们只需要1.7秒左右。我应该注意到,下面的两个表都超过了440,000行,但我并不认为它非常大。问题可能是我加入表格的方式或我创建子查询的方式。

这是我的设置:(它是导出表格中的SQL。我省略了一些列)

/**The table for Panama weather data */ 

CREATE TABLE `panama_weather_data` (
  `Id` varchar(40) NOT NULL,
  `OwmPackageId` varchar(30) NOT NULL,
  `Level` FLOAT DEFAULT NULL,
  `Dt` date DEFAULT NULL,
  `Temperature` float DEFAULT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `panama_weather_data`
  ADD PRIMARY KEY (`Id`) USING BTREE;
COMMIT;

/**The table for Belize weather data*/

CREATE TABLE `belize_weather_data` (
  `Id` varchar(40) NOT NULL,
  `OwmPackageId` varchar(30) NOT NULL,
  `Level` FLOAT DEFAULT NULL,
  `Dt` date DEFAULT NULL,
  `Temperature` float DEFAULT NULL,
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `belize_weather_data`
  ADD PRIMARY KEY (`Id`) USING BTREE;
COMMIT;

/**Code to populate the tables here*/

这是我的疑问:

SELECT ABS(PanamaTemperature-BelizeTemperature) AS TemperatureDif, 
PanamaAtmostphericLevel, PanamaTable.Dt
         FROM
         (SELECT CAST(panama_weather_data.Dt AS DATETIME) AS Dt,  
         panama_weather_data.Level AS PanamaAtmostphericLevel, 
         panama_weather_data.Temperature AS PanamaTemperature
         FROM panama_weather_data
         WHERE panama_weather_data.OwmPackageId = 'openweathermappkg19758'  ) 
         AS PanamaTable
         JOIN 
         (SELECT CAST(belize_weather_data.Dt AS DATETIME) AS Dt, 
         belize_weather_data.Level AS BelizeAtmosphericLevel, 
         belize_weather_data.Temperature AS BelizeTemperature
         FROM belize_weather_data
         WHERE belize_weather_data.OwmPackageId = 'openweathermappkg19758' ) 
         AS BelizeTable
         ON PanamaAtmostphericLevel = BelizeAtmosphericLevel
         AND PanamaTable.Dt = BelizeTable.Dt
         ORDER BY TemperatureDif
         LIMIT 30

我的问题是:无论如何要优化此查询并减少痛苦吗?

4 个答案:

答案 0 :(得分:1)

  

CAST(panama_weather_data.Dt AS DATETIME)AS Dt

为什么呢? (所有这一切都会减慢查询速度)

  

无论如何都要优化此查询

您向我们展示的SQL SELECT语句肯定会成为我的起点。但是,您没有告诉我们您将来如何查询数据。具体来说,您是否真的要在每次运行查询时检查所有数据?

您最大的胜利来自于不将数据保存在单独的表中 - 它应该是一个包含两个数据集的不同属性的表。

在那之后,下一个最大的改进将来自于存储表中的温度差并将其编入索引。

答案 1 :(得分:0)

在SQL数据库中大幅提高速度的一种方法是使用索引。这是磁盘空间和查询性能之间的权衡。

要找出放置索引的位置,请搜索限制结果集的条件。在您的情况下,两个表可能有几十万行,但您只需要其中30个,其大气水平和日期相等。你可能想在这两列上放一个索引,如下所示:

CREATE INDEX level_date_panama ON panama_weather_data (Level, Dt);
CREATE INDEX level_date_belize ON belize_weather_data (Level, Dt);

请告诉我这是否会提高您的表现。

答案 2 :(得分:0)

你可以做一些事情来改善绩效:

  1. 删除子查询。
  2. 根据您发布的内容,我看不出为什么子查询对于连接是必要的。您可以轻松地删除它们并使用实际的列名称重写,以代替您编写AS值的位置。

    1. 将您的Dt数据输入为日期时间
    2. CAST并不是一个特别昂贵的运营商,但确实需要时间来完成。如果您仅将这些列用作日期时间,则应该按原样输入它们并将列类型更改为Datetime。您可以直接比较这些值,而不必投射它们。

      1. 将Dt比作日期
      2. 离开(2),如果你所有的Dt值都是Dates,那么将它们转换为Datetimes不会对该值做任何事情,所以只需比较自然日期类型。

        1. 索引
        2. 如果由于外部限制而无法进行上述操作,请根据您的加入方式创建索引,这将是ON子句中使用的列。

答案 3 :(得分:0)

id中有哪些值?也许你可以摆脱id,并使用PRIMARY KEY(level, dt)

为什么levelFLOAT?如果它们真的是“浮动”值,那么两个表具有相同的值是否切合实际?我猜他们是海拔还是米?在这种情况下,MEDIUMINT UNSIGNED不会满足吗?

则...

SELECT  ABS(p.Temperature - b.Temperature) AS TemperatureDif,
        p.Level,
        p.Dt
    FROM  panama_weather_data AS p
    JOIN  belize_weather_data AS b
       USING (OwmPackageId, Level, Dt)
    WHERE  p.OwmPackageId = 'openweathermappkg19758'
    ORDER BY  TemperatureDif DESC
    LIMIT  30;

你需要

INDEX(OwmPackageId, Level, Dt)

以任何顺序列出这些列,以及任何一个(或两个)表。

如前所述,不需要CAST。但是,如果您需要"2017-08-13 10:04:12"以外的某种格式,请在DATE_FORMAT(...)子句中使用SELECT(而不是USING子句。)

不要让两个“相同”的表格,而是考虑让一个表格包含一个涉及哪个国家/地区的额外列。这样可以很容易地扩展到任意数量的位置。 SELECT需要是“自联接”,语法会略有不同。