0

这个查询引用了大约 3M 条记录,现在需要一个绝对时间才能运行。数据取自 Excel 电子表格,其中 Cust/Invoices 向下行,每月值 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';

解释产生:

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

从视觉上看,它说这是一个完整的索引扫描,我假设红色背景表明这很糟糕。

任何想法我可以如何进一步优化。

4

3 回答 3

0

您可以尝试以下类似的方法 - 使用 CTE 或临时表并使用案例和位置评估预期结果。在更新 put 适当的 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
)
于 2018-12-13T12:17:14.553 回答
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';

ref: EXISTS 是否比 COUNT(*)>0 更有效?

于 2018-12-13T11:06:12.053 回答
0

你有这个综合指数吗?还是从这两列开始的更广泛的索引?

INDEX(CustomerRef, TransMonth)   -- in either order

是否可以每月计算一次上个月的信息或部分信息?将其存储在汇总表中,然后查询该表可能是一种更快的方法。

您是否碰巧知道您是否受 I/O 限制?如果您是 I/O-bound,那么 的值是innodb_buffer_pool_size多少,您有多少 RAM,以及表有多大 (GB)?

于 2018-12-14T19:42:37.913 回答