我有一个相对简单的查询,它简单地总结了我的网站已接受的所有paypal付款,使用每天更新的货币转换表将它们全部转换为GBP。
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,000行,在CC中有5,000行,查询需要大约9秒,在一个功能强大的盒子上。
EXPLAIN显示了这个:
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 & mc_currency
上尝试了一个索引,在mc_currency & tIPN
上尝试了一个索引。没有帮助。我想也许DATE()
函数是问题,所以创建了一个列tIPNdate
并修改了相关的索引来代替使用它,它没有任何区别。
我觉得我错过了一些明显的东西,有人可以帮忙吗?
由于
答案 0 :(得分:1)
对于这么多数据而言,9秒并不是极端性能问题。
话虽如此,将其分解为两个不同的SUM()
操作可能是有意义的。
首先,查询GBP交易。
SELECT SUM(PPI.mc_gross)
FROM paypal_payment_info PPI
WHERE PPI.mc_currency = 'GBP'
(mc_currency, mc_gross)
上的复合索引将使查询尽可能快。这可能会使您获得大部分交易而无需任何连接。希望更快。
然后,处理非英镑交易。
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'
要清除JOIN的不可分割的DATE()
部分,请执行以下操作:
SELECT SUM(PPI.mc_gross * CC.fConv)
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'
不确定,我认为paypal_payment_info( tPN, mc_currency, mc_gross)
上的复合索引将有助于此查询。我认为currency_conversions (sFrom, tConv, fConv)
上的索引也会有所帮助。
然后,您可以使用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
答案 1 :(得分:1)
首先,我会通过在您的货币转换表中添加一行来select
转换为自己1.00
的费率来简化GBP
表达式。
接下来,恢复您的tIPNdate
列(值为DATE(PPI.tIPN)
) - 这肯定有帮助。
您需要currency_conversions
上的索引:
create index index_cc_001 on currency_conversions(tconv, sFrom, fConv);
会对您的查询产生最大影响。此外,索引中列的顺序很重要 - 始终首先放置最多变且完全匹配的列。
在paypal_payment_info
上创建索引:
create index index_ppi_001 on paypal_payment_info(tIPNdate, mc_currency, mc_gross);
这两个索引都是覆盖索引,这意味着可以在索引中找到查询所需的所有数据,从而避免了访问表的需要。
查询应如下(删除冗余部分后):
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
答案 2 :(得分:0)
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) FORCE INDEX (tIPN,mc_currency)