0

カーソルベースの更新を最適化するか、実際に置き換えることを検討しています...

状況

プロモーション キャンペーンを実施しており、キャンペーンごとのユーザー アクティビティを追跡したいと考えています。

論理

各キャンペーンは特定のバッチにプッシュされます - 当社の顧客ベースのセグメント

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 が自己参照クエリから更新を実行できないためです)。

私が明確であることを願っています & あなたのアイデアを前もって感謝します

4

1 に答える 1