Mysql 如何加速这个(相对简单的)查询

Mysql 如何加速这个(相对简单的)查询,mysql,Mysql,我有一个相对简单的查询,它简单地汇总了我的网站接受的所有贝宝付款,使用每天更新的货币转换表将它们全部转换为英镑 SELECT SUM(PPI.mc_gross * IF(PPI.mc_currency='GBP', 1, CC.fConv)) FROM paypal_payment_info PPI JOIN currency_conversions CC ON CC.sFrom = PPI.mc_currency AND CC.tConv = DATE(PPI.tIPN) PPI中有30

我有一个相对简单的查询,它简单地汇总了我的网站接受的所有贝宝付款,使用每天更新的货币转换表将它们全部转换为英镑

SELECT SUM(PPI.mc_gross * IF(PPI.mc_currency='GBP', 1, CC.fConv))

FROM paypal_payment_info PPI

JOIN currency_conversions CC ON CC.sFrom = PPI.mc_currency AND CC.tConv = DATE(PPI.tIPN)
PPI中有30000行,CC中有5000行,在一个强大的框中,查询大约需要9秒

解释表明:

id  select_type table   type    possible_keys   key key_len ref rows Extra
1   SIMPLE  PPI ALL                 31271   
1   SIMPLE  CC  ref sFrom   sFrom   9   db.PPI.mc_currency  1167    Using where
我尝试了一个关于tIPN和MCU货币的指数,以及一个关于MCU货币和tIPN的指数。两者都没有帮助。我认为可能是DATE函数出了问题,所以创建了一个列tIPNdate并修改了相关的索引以使用它,这没有任何区别

我觉得我错过了一些明显的东西,有人能帮忙吗


谢谢

对于这么多的数据来说,9秒并不是一个极端的性能问题

尽管如此,将其分解为两个不同的求和运算可能是有意义的

首先,对GBP交易进行查询

SELECT SUM(PPI.mc_gross)
  FROM paypal_payment_info PPI
 WHERE PPI.mc_currency = 'GBP'
SELECT SUM(PPI.mc_gross * CC.fConv)
  FROM paypal_payment_info PPI
  JOIN currency_conversions CC ON CC.sFrom = PPI.mc_currency 
                             AND CC.tConv = DATE(PPI.tIPN)
 WHERE PPI.mc_currency <> 'GBP'
mc_gross是一个关于mc_货币的复合索引,它将尽可能快地进行查询。这可能会让您获得大部分事务,而不需要任何连接。希望更快

然后,处理非GBP事务

SELECT SUM(PPI.mc_gross)
  FROM paypal_payment_info PPI
 WHERE PPI.mc_currency = 'GBP'
SELECT SUM(PPI.mc_gross * CC.fConv)
  FROM paypal_payment_info PPI
  JOIN currency_conversions CC ON CC.sFrom = PPI.mc_currency 
                             AND CC.tConv = DATE(PPI.tIPN)
 WHERE PPI.mc_currency <> 'GBP'
不确定的是,我认为paypal_payment_info tPN、mc_currency、mc_gross上的复合索引将有助于此查询。我认为一个关于货币转换的指数也会有所帮助

然后可以使用UNION ALL和另一个SUM添加两个查询的结果

SELECT SUM(sums) sums
  FROM (
              SELECT SUM(PPI.mc_gross) sums
                FROM paypal_payment_info PPI
               WHERE PPI.mc_currency = 'GBP'
      UNION ALL
              SELECT SUM(PPI.mc_gross * CC.fConv) sums
                FROM paypal_payment_info PPI
                JOIN currency_conversions CC ON PPI.mc_currency = CC.sFrom
                                            AND PPI.tPN >= CC.tConv
                                            AND PPI.tPN <  CC.tConv + INTERVAL 1 DAY
               WHERE PPI.mc_currency <> 'GBP'
       ) s

首先,我将简化select表达式,在货币转换表中添加一行,将英镑转换为自身的汇率为1.00

接下来,恢复tIPNdate列,使其值为DATEPPI.tIPN-这肯定会有所帮助

您需要关于货币换算的索引:

这将对您的查询产生最大影响。此外,索引中列的顺序也很重要-始终将变化最大且完全匹配的列放在第一位

并在paypal\u payment\u信息上创建索引:

这两个索引都是覆盖索引,这意味着查询所需的所有数据都可以在索引中找到,从而避免了访问表的需要

删除冗余零件后的查询应如下所示:

SELECT SUM(mc_gross * fConv)
FROM paypal_payment_info
JOIN currency_conversions ON sFrom = mc_currency
    AND tConv = tIPNdate
最后,您可能会发现颠倒表的顺序效果更好:

SELECT SUM(mc_gross * fConv)
FROM currency_conversions
JOIN paypal_payment_info ON sFrom = mc_currency
    AND tConv = tIPNdate

你能编辑这篇文章并解释一下这段代码是如何使SQL更快的吗?只有代码的答案并不总是很有用……特别是当OP在问题中陈述他们已经尝试在tIPN和mc_Currency上建立索引时,这是连接两个完整的表。为什么你认为它会很快?这确实使它下降到3.5秒左右,但由于它是一个非常简单的和/积,在相对较少的行数上,我仍然觉得它应该快得多,几乎是即时的。也许我不得不放弃,并将货币转换存储在PPI表中,与每笔交易一起。尝试以下索引:paypal\u payment\u infomc\u currency、mc\u gross、tIPN、currency\u conversionstConv、sFrom、FCONVac。实际上,首先在原始查询上尝试这些索引,然后查看其执行情况。我不确定我是否理解清理无法组织的东西的方法。。。这是答案的一部分。感谢您的贡献,但在您键入时,我正忙于更改模式,以便将货币转换存储在PPI表中,与每笔交易一起。现在是0.05秒。也许我可以修复原来的查询,但这似乎简单、直接,并且易于维护。
SELECT SUM(mc_gross * fConv)
FROM paypal_payment_info
JOIN currency_conversions ON sFrom = mc_currency
    AND tConv = tIPNdate
SELECT SUM(mc_gross * fConv)
FROM currency_conversions
JOIN paypal_payment_info ON sFrom = mc_currency
    AND tConv = tIPNdate