【发布时间】:2015-03-27 11:24:22
【问题描述】:
我正在寻找优化基于光标的更新或实际替换它...
情况
我们正在开展促销活动,我想跟踪每个活动的用户活动。
逻辑
每个广告系列都被推送到特定批次 - 我们客户群的细分
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
默认情况下,segments 表中的 tracking_end_date 设置为当月的最后一天,但我创建了一个程序来检查和更新此字段。 (Campaign_id 是根据活动日期顺序发布的,因此最早的活动具有最少的活动 ID 值,反之亦然) 跟踪是按月按月进行的。
更新场景
对于分段表中的每条记录,检查相同的 customer_id 是否出现在未来的活动中,以及具有更大 tracking_start_date 的活动是否具有相同的 CTA。
如果为真:将该记录的 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 的segments 表中复制一份并从那里进行比较(这是因为MySQL 无法从自引用查询中进行更新)
希望我很清楚并提前感谢您的想法
【问题讨论】:
-
您可以使用自联接而不是子查询来引用
UPDATE中的同一个表。 -
谢谢巴马尔。愿意分享一下你是如何写这篇文章的吗?
标签: mysql stored-procedures query-performance cursors