カーソルベースの更新を最適化するか、実際に置き換えることを検討しています...
状況
プロモーション キャンペーンを実施しており、キャンペーンごとのユーザー アクティビティを追跡したいと考えています。
論理
各キャンペーンは特定のバッチにプッシュされます - 当社の顧客ベースのセグメント
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 は追跡を終了する日付です。
各キャンペーンには独自の「Call to Action (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 はキャンペーンの日付に従って順次発行されるため、最初のキャンペーンが最も小さい Campaign_id 値を持ち、その逆も同様です) 追跡は、カレンダーの月ごとに行われます。
シナリオの更新
セグメント テーブルの各レコードについて、同じ customer_id が将来のキャンペーンに表示されるかどうか、および tracking_start_date が大きいキャンペーンの CTA が同じかどうかを確認します。
TRUE の場合: そのレコードの tracking_end_date を新しいキャンペーンの前日に変更します。
FALSE の場合: tracking_start_date 月の最終日を tracking_end_date として保持します。
更新が行われない場合、複数のキャンペーンに登場し、同じ CTA を持つ顧客のトランザクションを 2 倍または 3 倍にカウントすることになります。
以下は私が現在使用している手順ですが、問題は遅すぎることです。
これらのプロシージャは、その月の 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 という別のテーブルにセグメント テーブルのコピーを作成し、そこから比較を行います (これは、MySQL が自己参照クエリから更新を実行できないためです)。
私が明確であることを願っています & あなたのアイデアを前もって感謝します