【问题标题】:Optimizing MySQL update query优化 MySQL 更新查询
【发布时间】:2011-06-09 09:43:36
【问题描述】:

这是目前我的 MySQL UPDATE 查询,它是从用 Java 编写的程序中调用的:

String query = "UPDATE maxday SET DatePressureREL = (SELECT " + 
   "Date FROM ws3600 WHERE PressureREL = (SELECT MAX" +
   "(PressureREL) FROM ws3600 WHERE Date >= '" + Date + 
   "') AND Date >= '" + Date + "' ORDER BY Date DESC LIMIT 1), " +
   "PressureREL = (SELECT PressureREL FROM ws3600 WHERE " + 
   "PressureREL = (SELECT MAX(PressureREL) FROM ws3600 " +
   "WHERE Date >= '" + Date + "') AND Date >= '" + Date + 
   "' ORDER BY Date DESC LIMIT 1), ...";

try {
    s.execute(query);
} 
catch (SQLException e) {
    System.out.println("SQL error");
}
catch(Exception e) {
    e.printStackTrace();
}

让我先解释一下,它是做什么的。我有两个表,第一个是 ws3600,它包含列(Date、PressureREL、TemperatureOUT、Dewpoint,...)。然后我有第二个表,称为 maxday,其中包含 DatePressureREL、PressureREL、DateTemperatureOUT、TemperatureOUT 等列...现在您可以从一个示例中看到,我更新了每一列,问题是,有没有更快的方法?我问这个,因为我调用 MAX 两次,首先是找到该值的日期,其次是找到实际值。现在我知道我可以这样写:

SELECT Date, PressureREL FROM ws3600 WHERE PressureREL = 
  (SELECT MAX(PressureREL) FROM ws3600 WHERE Date >= '" + 
  Date + "') AND Date >= '" + Date + "' 
ORDER BY Date DESC LIMIT 1

这样我可以同时获得最大值和最大值的日期,然后用这些值更新 maxday 表中的数据。但是这个解决方案的问题是,我必须执行许多查询,据我所知,与执行一个长的 mysql 查询相比,这需要更多的时间,因为将每个查询发送到服务器的开销。

如果没有更好的方法,我应该选择这两个之间的哪个解决方案。第一个,只需要一个查询但非常未优化,或者第二个在优化方面更好,但需要更多的查询,这可能意味着性能增益会因为将每个查询发送到服务器的开销而损失?

【问题讨论】:

  • 星期五晚上太晚了,我什至无法开始思考这个问题:P
  • 关于第二个子句Date,在Serinus指出并得出一个我可能不需要的结论后,我又研究了一些,因为我用DESC LIMIT 1限制了结果。只是没有第二个子句并且没有 DESC LIMIT 1,它将返回整个表中等于该 MAX 值的所有值,而不仅仅是那些受参数 Date 限制的值。我仍然想知道我的问题的真正答案。

标签: java mysql optimization


【解决方案1】:

执行 2 次查询对我来说并不是问题,但它们应该在一个事务中(读取和写入),这样您就可以确保您的更新值没有错误。一个查询就没有这个问题。

我认为读取某些数据所损失的时间与执行写入操作所损失的时间无关。根据定义,写入操作并不是一件快速的事情,您可能有触发器,您可能正在清空影响该表的所有请求的查询缓存,数据库需要同步您在磁盘上的写入,等等。

对你来说更重要的是保持你的过程简单、可读和逻辑。

【讨论】:

  • 问题是,如果选择第二种解决方案,将会有两个以上的查询(10 个查询),这只是为了找到最大值。因此,如果我使用更多查询,我将有 20 个查询(最大和最小),但如果我使用第一个解决方案,我将有 2 个查询。所以你认为如果我必须发送 20 个查询而不是 2 个查询,它不会影响性能?
  • 19 次读取查询和 1 次写入,或者执行相同操作的一次大写入,除非您有大的 tcp/ip 问题……好吧,我不确定。您也可以在存储过程中执行此操作,编译代码,查询的数量并不重要,但每个查询所花费的时间很重要。测试一下。
【解决方案2】:

1) 我认为问题不仅仅是 SQL 优化。您是否认为这可以以不同的方式建模,因为您不必首先迁移这样的数据(这么多,而且这通常也是如此)?也许只是使用 FK/交叉表将两者链接在一起而不是迁移每个字段?

2) 一个查询比使用 JDBC 不断地在新语句的连接上来回走动要好得多。这是一个非常昂贵的操作(每次)。您总是希望坚持将查询压缩为一个,而不是使用迭代来执行许多语句。

【讨论】:

  • 好的,所以第一个解决方案看起来越来越好。但是您仍然可以回答缩短第一个解决方案的部分吗?正如我上面的评论,我知道第二个子句可以删除,但是关于两次选择 MAX 值的主要部分仍然让我很头疼。
【解决方案3】:

从内到外,看起来您的所有子查询都在做同样的事情。

有一个 where 子句执行 Date >= '" + Date + "') AND Date >= '" + Date + "' 有什么意义?

在不涉及列名或技术细节的情况下,您的两个表的用途是什么?

String query = @"UPDATE maxday SET DatePressureREL = (SELECT Date FROM ws3600 WHERE PressureREL = (SELECT MAX(PressureREL) FROM ws3600 WHERE Date >= @Date) AND Date >= @Date ORDER BY Date DESC LIMIT 1), PressureREL = (SELECT PressureREL FROM ws3600 WHERE PressureREL = (SELECT MAX(PressureREL) FROM ws3600 WHERE Date >= @Date) AND Date >= @Date ORDER BY Date DESC LIMIT 1), ...";

在此之后,理想情况下,如果您使用某种类型的 SelectCommand 而不是字符串,您会

query.Parameters.Add(new MySqlParameter("@Date", yourdate));

或者,您也可以这样做,尽管它会打开 sql 注入

query = query.replace("@Date", "'" + Date "'");

无论哪种方式,它都会使查询更加清晰。

【讨论】:

  • 另外,这可能有助于提高可读性。 C# 中字符串前的 @ 符号将允许您在多行中拥有一个字符串。
  • 我需要两个子句来检查Date,第一个限制选择相对压力的时间,检查Date的内部子句是在有限的时间内选择MAX。
【解决方案4】:

如果您可以在一个选择查询中获取所有值,这可能会起作用。使用接受一个参数(日期)的存储过程:

一个选择语句,将值存储在游标中,并且

一个更新语句,使用游标中的值。

Cursor Example

【讨论】:

    猜你喜欢
    • 2017-12-30
    • 1970-01-01
    • 1970-01-01
    • 2021-07-10
    • 2015-11-08
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多