【问题标题】:Optimized SQL query when there's no physical connection between tables表之间没有物理连接时的优化 SQL 查询
【发布时间】:2015-10-26 20:38:34
【问题描述】:

当表之间没有逻辑连接时,我需要帮助来编写更优化的 SQL 查询。我写了一些子查询,但我对它不满意,因为我重复了几乎相同的子查询两次。
方案是这样的:

create table rate (
  rate_date date,
  value decimal(10,2),
  multiplier integer,
  name varchar(3)
  );

create table amount (
  amount decimal(10,2),
  amount_year date,
  rate_name varchar(3)
  );


我希望AMOUNT 表中的每个金额都使用RATE 表中的乘数和比率值来计算,例如amount / multiplier * rate。两个表的共同点是名称(一些代码标识符)和日期。这些应该用于将数据汇总在一起。仅考虑 amount_year 的最新费率。
如果您愿意提供帮助,可以查看此fiddle。这是我的尝试。

select am.amount / 
    (
      select ra.multiplier 
      from rate ra
      where ra.rate_date = (select max(rate_date) 
                            from rate 
                            where year(rate_date) = year(am.amount_year) and name = am.rate_name) 
        and ra.name = am.rate_name
    ) * (
      select ra.value 
      from rate ra
      where ra.rate_date = (select max(rate_date) 
                            from rate 
                            where year(rate_date) = year(am.amount_year) and name = am.rate_name) 
        and ra.name = am.rate_name
    ) as calculated_amount
    from amount am;

【问题讨论】:

  • “表之间没有物理连接”是什么意思?它们在不同的数据库服务器上?
  • @Barmar 没有外键,没有索引等。假设它们可能在不同的架构上。
  • 所以你的意思是没有逻辑连接。
  • @Barmar 你是对的。我编辑了我的帖子。

标签: mysql sql join subquery sql-optimization


【解决方案1】:

您的子查询是相同的,因此您可以一次完成工作:

select am.amount / 
       (select ra.multiplier * ra.value
        from rate ra
        where ra.rate_date = (select max(rate_date) 
                              from rate 
                              where year(rate_date) = year(am.amount_year) and name = am.rate_name)  and ra.name = am.rate_name
                             )
       ) as calculated_amount
from amount am;

或者这可以表述为:

select am.amount / 
       (select ra.multiplier * ra.value
        from rate ra
        where year(ra.rate_date) = year(am.amount_year) and name = am.rate_name
        order by ra.rate_date desc
        limit 1
       ) as calculated_amount
from amount am;

如果您愿意,您可以使用带有where 子句的join 来执行此操作:

select (am.amount / ra.multiplier * ra.value) as calculated_amount
from amount am join
     rate ra
     on ra.name = am.name and
        year(rate_date) = year(am.amount_year)
where ra.date = (select max(r2.rate_date)
                 from rate r2
                 where year(r2.rate_date) = year(r.rate_date) and
                       r2.name = ra.name
                );

为了提高性能,请从rate(name, rate_date, multiplier, value) 上的索引开始。对于任一查询。

为了获得更好的性能,您可能需要将“年份”作为单独的列存储在表中。

【讨论】:

    【解决方案2】:

    您可以使用单个子查询来获取每年的最新倍数和值。然后将其与amount 表连接起来进行除法。

    SELECT am.amount / (r2.multiplier * r2.value) AS calculated_amount
    FROM amount AS am
    JOIN (SELECT YEAR(rate_date) AS year, MAX(rate_date) AS maxdate
          FROM rate
          GROUP BY year) AS r1 ON YEAR(am.rate_date) = r1.year
    JOIN rate AS r2 ON r1.maxdate = r2.rate_date
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-16
      • 2017-04-24
      • 2018-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-15
      • 1970-01-01
      相关资源
      最近更新 更多