0

ウェブベースのアプリの使用状況を分析しようとしています。次の列のメールアドレスの活動日を含むテーブルがあります

この質問に答えるクエリを作成したいと思います: 過去 180 日間の各日について、ALSO で 60 ~ 30 日前にアクティビティを行った人のうち、30 ~ 0 日前にアクティビティを行った人の数。

過去 180 日間 (1 日 1 行の日付テーブルを使用) を文字通りループするストアド プロシージャとして既にこれが機能していますが、180 のクエリを実行しているため、これは少し遅いです。

また、IN句を使用した1つのクエリでそれを実行しようとしましたが、完了するまでに約5分かかりました(テーブルには合計約2,000行しかないため、最適化されていないと推測しています)

最適化された 1 つのクエリ (またはストアド プロシージャ) でこれを行うにはどうすればよいでしょうか?

役立つ場合は、現在のストアド プロシージャ (動作しますが遅い) を次に示します。

BEGIN
    DECLARE mydate DATE;
    DECLARE period1 INT;
    DECLARE period2 INT;
    DECLARE done INT;

    DECLARE cur CURSOR FOR SELECT date_value from dim_date  order by date_value DESC;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
    SET done = 0;
    OPEN cur;

    REPEAT

    FETCH cur INTO mydate;
    IF NOT done THEN
  REPLACE INTO churn (payment_received,period2,period1,churn_name)

    select
mydate, 
count(distinct(case when (sales.payment_received BETWEEN DATE_SUB(mydate,INTERVAL p2 month) AND DATE_SUB(mydate,INTERVAL p1 month)) then email end)) AS period2,
(
select count(distinct(case when (sales.payment_received BETWEEN DATE_SUB(mydate,INTERVAL p1 month) AND mydate) then email end))
from sales where subscription = 1 AND email in (select email from sales where sales.payment_received BETWEEN DATE_SUB(mydate,INTERVAL p2 month) AND DATE_SUB(mydate,INTERVAL p1 month) ) 
) 
AS period1,
churn_name as cname
from sales 
where subscription = 1;

    END IF;    
    UNTIL done END REPEAT;
    CLOSE cur;

END;;

ありがとう!

4

2 に答える 2

0

ステップ 1) 先月のアクティビティを持つユーザーを取得します (DISTINCT は先月の回数は気にしないため、ユーザーがアクティブだった天候だけです):

SELECT DISTINCT email
FROM sales 
WHERE payment_received BETWEEN NOW() AND DATE_ADD(NOW(),INTERVAL -1 MONTHS)

ステップ 2) 1 ~ 2 か月前にアクティビティがあったユーザーを取得します。

SELECT DISTINCT email
FROM sales 
WHERE payment_received BETWEEN DATE_ADD(NOW(),INTERVAL -1 MONTHS) AND DATE_ADD(NOW(),INTERVAL -2 MONTHS)

ステップ 3) これらを 1 つの結果セットに結合する

SELECT M1.email
FROM (
  SELECT DISTINCT email
  FROM sales 
  WHERE payment_received BETWEEN NOW() AND DATE_ADD(NOW(),INTERVAL -1 MONTHS)
) M1,
(
  SELECT DISTINCT email
  FROM sales 
  WHERE payment_received BETWEEN DATE_ADD(NOW(),INTERVAL -1 MONTHS) AND DATE_ADD(NOW(),INTERVAL -2 MONTHS)
) M2
WHERE M1.email = M2.email
于 2013-03-15T16:47:35.457 に答える
0

先に進み、それdim_dateがカレンダー テーブルであると仮定します (非常に便利なものです) また、(もしあれば) どんなインデックスを持っているかを知っておくとよいかもしれませんが、2000 行の場合、適切な RDBMS はテーブル全体を次の場所にロードする可能性がありますメモリに関係なく、それはおそらく要因ではありません。

残念ながら、どう見てもこの種の分析には時間がかかります。これを完全にセットベースのアプローチに変換すると速度が上がると確信していますが、実際にテストするインスタンスがありません。ステートメントを次のように書き直すことから始めます。

SELECT Dim_Date.date_value, 
       COUNT(DISTINCT Period_2.email), COUNT(DISTINCT Period_1.email),
       Period_1.churn_name
FROM Dim_Date
JOIN Sales Period_2
  ON Period_2.payment_received >= DATE_SUB(Dim_Date.date_value, INTERVAL 60 DAY)
     AND Period_2.payment_received < DATE_SUB(Dim_Date.date_value, INTERVAL 30 DAY)
     AND Period_2.subscription = 1
LEFT JOIN Sales Period_1
       ON Period_1.payment_received >= DATE_SUB(Dim_Date.date_value, INTERVAL 30 DAY)
          AND Period_1.payment_received < Dim_Date.date_value
          AND Period_1.subscription = 1
          AND Period_1.email = Period_2.email
          AND Period_1.churn_name = Period_2.churn_name
WHERE Dim_Date.date_value >= DATE_SUB(CURRENT_DATE, INTERVAL 180 DAY)
      AND Dim_Date.date_value < CURRENT_DATE
GROUP BY Dim_Date.date_value, Period_1.churn_name

このステートメントは実行されるはずですが、それ以外はテストされていません。
(...最初にここで何を考えていたのかわかりません。ユーザーごとに 2 つのセットを関連付けていませんでした...)

subscription = 11 つ-最も内側のサブクエリの条件として持っていないようです。それが意図的なものなのか、見落としなのか、私にはわかりませんでした。churn_nameまた、それが何であれ、相関する必要があると想定しました。

于 2013-03-15T17:31:24.387 に答える