我希望优化基于光标的更新或实际替换它......
场合
我们正在开展宣传活动,并且我希望跟踪每个广告系列的用户活动。
逻辑
每个广告系列都会推送到特定批次 - 我们客户群的细分
CREATE TABLE `segments` (
`campaign_id` int(6) DEFAULT NULL,
`customer_id` varchar(20) DEFAULT NULL,
`tracking_start_date` date DEFAULT NULL,
`tracking_end_date` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
tracking_start_date是广告系列的日期,而tracking_end_date是日期跟踪应该结束。
每个广告系列都拥有它自己的行动(cta)"这是我们推动并希望客户在广告系列之后开始使用的交易类型。
CREATE TABLE `cta` (
`campaign_id` int(11) DEFAULT NULL,
`Date` date DEFAULT NULL,
`segment` varchar(100) DEFAULT NULL,
`message` varchar(320) DEFAULT NULL,
`Size` int(11) DEFAULT NULL,
`cta` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
默认情况下,细分表中的tracking_end_date设置为该月的最后一天,但我已创建了检查和更新此字段的过程。 (Campaign_id' s根据广告系列日期顺序发布,因此最早的广告系列具有最少的campaign_id值,反之亦然) 跟踪是在每月的日历上完成的。
更新方案
对于细分表格中的每条记录,请检查以后的广告系列中是否显示相同的customer_id,以及具有更高tracking_start_date的广告系列是否具有相同的CTA。
如果为TRUE:将该记录的tracking_end_date更改为新广告系列之前的一天。
如果为FALSE:将tracking_start_date月的最后一天保留为tracking_end_date。
如果没有完成更新,那么我们就会为那些出现在多个广告系列并拥有相同CTA的客户计算双重/三重计数。
以下是我目前正在使用的程序,但问题是它太慢了。
这些程序位于另一个程序中,该程序循环播放该月份的campaign_id,然后在提供相关的campaign_id时调用此程序
CREATE DEFINER=`root`@`localhost` PROCEDURE `set_campaign_end_date_child`(IN var_campaign_id INT)
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE var_customer_id VARCHAR(20);
DECLARE var_tracking_start_date DATE;
DECLARE cur1 CURSOR FOR SELECT DISTINCT customer_id FROM segments WHERE campaign_id =var_campaign_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- perform cursur update loop now
OPEN cur1;
read_loop: LOOP
IF done THEN
LEAVE read_loop;
END IF;
FETCH cur1 INTO var_customer_id;
SELECT DISTINCT DATE INTO var_tracking_start_date FROM cta WHERE campaign_id = var_campaign_id;
UPDATE segments SET tracking_end_date =
(SELECT IFNULL(DATE_SUB(MIN(tracking_start_date),INTERVAL 1 DAY),LAST_DAY(var_tracking_start_date)) FROM segments_temp
WHERE customer_id = var_customer_id
AND campaign_id
IN(SELECT campaign_id FROM cta WHERE cta IN (SELECT cta FROM cta WHERE campaign_id = var_campaign_id)
AND campaign_id > var_campaign_id))
WHERE customer_id = var_customer_id AND campaign_id =var_campaign_id ;
END LOOP read_loop;
CLOSE cur1;
END$$
DELIMITER ;
PS:在启动程序之前,我在另一个名为segments_temp的段中复制了segment表,并从那里进行比较(这是因为MySQL不能从自引用查询中进行更新)
希望我清楚& amp;提前感谢您的想法
答案 0 :(得分:1)
使用自我JOIN可以两次引用segments
表。如果我正确理解您的代码,我认为这是等效的更新:
UPDATE segments AS s1
LEFT JOIN (SELECT customer_id, DATE_SUB(MIN(tracking_start_date),INTERVAL 1 DAY) AS new_tracking_start_date
FROM segments AS s2
WHERE campaign_id IN (
SELECT campaign_id
FROM cta
WHERE cta IN (
SELECT cta
FROM cta
WHERE campaign_id = var_campaign_id)
AND campaign_id > var_campaign_id)
GROUP BY customer_id) AS s3
ON s1.customer_id = s3.customer_id
SET tracking_end_date = IFNULL(new_tracking_start_date, LAST_DAY(tracking_start_date))
WHERE campaign_id = var_campaign_id