此查询引用了约3M条记录,现在需要绝对时间才能运行。 数据取自Excel电子表格,其中“客户/发票”向下行,而月度值2016变为当前列。
此查询检查是否在同一月份中有相同/不同产品的值,如果可以忽略,则输出1,如果以后的查询应考虑为0,则输出。
我已经为产品设置了一个索引,该索引可以满足初始条件,但是绝对可以杀死它的是子查询:
UPDATE tbl_transactions a
SET ProdInCust_Mnth_Same_SameProd_LowerVal =
CASE WHEN
(
SELECT COUNT(TransactionID)
FROM tbl_transactions_tmp b
WHERE
b.TransactionID<>a.TransactionID AND
b.CustomerRef=a.CustomerRef AND
b.TransMonth=a.TransMonth AND
(
(
(b.Product='PLATINUM') AND
b.TransValue<0
)
OR
(
a.TransValue=0 AND
(b.Product='PLATINUM' OR b.Product='GOLD' OR b.Product='SILVER') AND
b.TransValue<0
)
OR
(
a.TransValue<0 AND
(b.Product='PLATINUM' OR b.Product='GOLD') AND
((b.TransValue=a.TransValue AND b.RowReference>a.RowReference) OR
b.TransValue<a.TransValue
)
)
)
)>0 THEN 1 ELSE 0 END
WHERE Product='GOLD';
EXPLAIN产生:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 UPDATE a \N index IDX_tbl_transactions_Product PRIMARY 8 \N 2828152 100 Using where
2 DEPENDENT SUBQUERY b \N ref IX_Transactions_SP_ProcessTransAA IX_Transactions_SP_ProcessTransAA 45 finance.a.CustomerRef,finance.a.TransMonth 1 20.7 Using where; Using index
从视觉上看,它表示这是一次全索引扫描,我认为红色背景表明这很不好。
关于如何进一步优化这一点的任何想法。
答案 0 :(得分:0)
尝试将子查询的WHERE子句中使用的所有字段的索引添加到两个表,并使用EXISTS
代替COUNT
:
UPDATE tbl_transactions a
SET ProdInCust_Mnth_Same_SameProd_LowerVal =
CASE WHEN EXISTS
(
SELECT TransactionID
FROM tbl_transactions_tmp b
WHERE
b.TransactionID<>a.TransactionID AND
b.CustomerRef=a.CustomerRef AND
b.TransMonth=a.TransMonth AND
(
(
(b.Product='PLATINUM') AND
b.TransValue<0
)
OR
(
a.TransValue=0 AND
(b.Product='PLATINUM' OR b.Product='GOLD' OR b.Product='SILVER') AND
b.TransValue<0
)
OR
(
a.TransValue<0 AND
(b.Product='PLATINUM' OR b.Product='GOLD') AND
((b.TransValue=a.TransValue AND b.RowReference>a.RowReference) OR
b.TransValue<a.TransValue
)
)
)
) THEN 1 ELSE 0 END
WHERE Product='GOLD';
答案 1 :(得分:0)
您可以尝试以下方法吗? 使用CTE或临时表并使用case和where评估预期结果。更新时使用此表值放在适当的位置。 希望这可以帮助您创建查询。查询可能不会给出确切的结果,但可以帮助您创建查询。
UPDATE a
SET ProdInCust_Mnth_Same_SameProd_LowerVal = c.val
tbl_transactions a
JOIN cte c on a.TransactionID = c.TransactionID
--WHERE Product='GOLD';
WITH cte AS
(
SELECT b.TransactionID, b.CustomerRef,b.TransMonth,b.TransValue, COUNT(TransactionID) ,
case when COUNT(TransactionID) > 0 then 1 else 0 END as val
FROM tbl_transactions_tmp b
WHERE
-- b.TransactionID<>a.TransactionID AND
-- b.CustomerRef=a.CustomerRef AND
b.TransMonth=a.TransMonth AND
(
(
(b.Product='PLATINUM') AND b.TransValue<0
)
OR
(
b.TransValue=0 AND
(b.Product='PLATINUM' OR b.Product='GOLD' OR b.Product='SILVER') AND
b.TransValue<0
)
OR
(
b.TransValue<0 AND
(b.Product='PLATINUM' OR b.Product='GOLD') AND
((b.TransValue=a.TransValue AND b.RowReference>a.RowReference) OR
b.TransValue<a.TransValue
)
)
)
)
group by b.CustomerRef
)
答案 2 :(得分:0)
您有此综合索引吗?还是从这两列开始以更宽的索引开始?
INDEX(CustomerRef, TransMonth) -- in either order
是否可以上个月每月一次计算信息或部分信息?将其存储在摘要表中,然后查询该表可能是一种更快的方法。
您碰巧知道您是否受I / O约束吗?如果您是受I / O限制的,innodb_buffer_pool_size
的值是多少?您有多少RAM?表有多大(GB)?