2017-07-28 37 views
0

我对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 

我的问题是真的:是无论如何要优化这个查询,并使其不那么痛苦?

回答

1

CAST(panama_weather_data.Dt AS DATETIME)AS申

为什么? (这一切都将做的是减缓查询)

反正是有优化这个查询

你对我们肯定会是我的出发点SQL SELECT语句。但是,您未告诉我们您将来如何打算查询数据。具体而言,您是否真的要在每次运行查询时检查所有数据?

您最大的收获来自于不将数据保存在单独的表格中 - 它应该是具有不同属性的单个表格用于两个数据集。

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

+0

对DATETIME进行强制转换是必要的(IMO),因为我最终需要将日期解析为JavaScript日期对象,并且在服务器上预先处理它们会更快。不幸的是,每次都需要评估所有数据,以生成一个图表,显示每个大气层的温度差异。你的建议(重构数据库)正是我想要避免的。我将这些数据作为两个单独的文件接收,并希望将这些信息分开,因为它更简单。显然不是。荣誉。 – SilentStone

+0

然后转换查询的输出 - **不要**加入计算字段上的表 – symcbean

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); 

请告诉我,这是否会增加您的表现。

+0

我不希望这会提高性能 - 如果索引减少从数据库中读取的行数或改进访问路径,它只会提高性能;如果MySQL的版本支持合并连接,那么2个索引中的一个可能会稍微加快速度,但并不是很重要。 – symcbean

+0

当将表A中的每条记录与来自表B的记录交叉时,表B上的索引将有助于更快地找到该记录..我没有可用的数据集,但查看查询,我不希望其他任何内容大大提高了运算速度。 – ggradnig

+0

您正在描述嵌套连接 - 在读取表中的所有记录时效率非常低。 – symcbean

0

你可以做一些事情在这里有可能提高性能:

  1. 删除子查询。

从你发布的内容看,没有理由为什么子查询是连接所必需的。您可以轻松地删除它们,并使用实际的列名称来代替您写入AS值的位置。

  • 输入您的申数据作为日期时间
  • CAST不是特别昂贵的操作,但确实需要时间来完成。如果您仅将这些列用作日期时间,则应该按照这种方式输入它们,并将列类型更改为日期时间。您可以直接比较这些值,而不必投射它们。

  • 比较申作为一个日期
  • 变成为关(2),如果您的所有dt值的日期,他们铸造日期时间不会做任何事该值,所以只需比较自然的Date类型。

  • 指数
  • 如果上述是不可能的,由于外部的限制,创建基于你如何加入一个索引,这将是在使用的柱条款。

    0

    id是什么样的值?也许你可以摆脱id,并使用PRIMARY KEY(level, dt)

    为什么level a FLOAT?如果它们真的是“浮动”的值,那么这两个表具有相同的值是否现实?我猜他们是海拔高度是英尺还是米?在这种情况下,会不会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"以外的其他格式,请在SELECT子句中使用DATE_FORMAT(...)(而不是USING子句)。

    而不是有两个'相同'表,考虑有一个表与一个额外的列涉及国家。这可以很容易地扩展到任意数量的位置。 SELECT需要是“自我连接”,语法稍有不同。