web-dev-qa-db-ja.com

予算のデータベース設計シナリオ(全体および毎日)

シナリオ:各ユーザーは自分のアカウントに資金(たとえば100 USD)を追加し、システム(私たちのWebサイト)は自分の広告をWebサイトに表示するために1日あたり最大10 USDを費やすことができると定義しています。または広告がウェブサイトに表示されるたびに、1米ドルの費用がかかります。

PS:広告が表示されるたびにレコードをデータベースに挿入するのではなく、広告を表示するための金額(1 USD)だけをdeduct予算。

表示する広告が多すぎるため、各広告ショーのレコードをデータベースに挿入することはできません。

Usersテーブルにはwhole_budgetdaily_budgetの2つの列があるため、上記のユーザーの場合、whole_budget100で、daily_budget10です。

上記のシナリオでは、daily budgetをどのように管理できますか?広告が表示されたら、彼のアカウントから1 USDをどのように差し引くのでしょうか。

彼が1日の予算を残したかどうかをどのように知ることができますか?その日の残りの時間に彼の広告を表示するかどうかを決めることができます。

よろしくお願いします

編集---------------

これは、shown_adsというテーブルを作成することで簡単に実現できます。広告を表示するたびに、尊重されたDATE()を使用してこのテーブルにレコードを挿入し、後で彼がすでに費やした彼の予算額を計算できるようにします今日。しかし、毎日1M広告を表示しているとしましょう。私が信じていることは、毎日100万件のレコードを挿入するのはよくないことです!これは単なるケーススタディです。これをどのように実装するか知りたいです。

2
behz4d

(おそらく)最も簡単な解決策は次のとおりです。

各キャンペーンの予算全体について1つのテーブルを用意します(ユーザーが一度に複数の広告を表示できるようにします:-)。

CREATE TABLE budget
(
    campaign_id INTEGER PRIMARY KEY, 
    user_id INTEGER REFERENCES users(user_id),
    /* Assumption: your currency doesn't have decimals; or you're using cents
       as currency unit */
    original_budget    INTEGER NOT NULL,  
    available_budget   INTEGER NOT NULL,
    daily_budget_limit INTEGER NOT NULL,

    -- Security checks
    CHECK(original_budget > 0),
    CHECK(original_budget >= available_budget),
    CHECK(daily_budget_limit > 0),
    CHECK(daily_budget_limit <= original_budget)
) ;

todayだけの予算のsecondテーブルがあります

CREATE TABLE todays_budget
(
    campaign_id INTEGER NOT NULL REFERENCES budget(campaign_id) PRIMARY KEY,
    original_daily_budget INTEGER NOT NULL,
    available_daily_budget INTEGER NOT NULL,

    CHECK(available_daily_budget >= 0)
) ;

毎日00:00に、次の操作を実行します。

  1. budgetからspent_budgetoriginal_daily_budget - available_daily_budget)を減算します
  2. DELETEtodays_budgetのすべて
  3. INSERTtodays_budgetへの新しい行。original_dailyとavailable_dailyの両方の予算は、(daily_budget_limit、available_budget)の最小値に等しい

これは、次のクエリで実行できます。

  1. 昨日から残りを引く

    UPDATE 
        budget
    SET
        available_budget = available_budget - 
            (SELECT
                original_daily_budget - available_daily_budget
            FROM
                todays_budget tod
            WHERE
                tod.campaign_id = budget.campaign_id)
     WHERE
          campaign_id IN 
              (SELECT 
                  campaign_id 
              FROM 
                  todays_budget 
              WHERE 
                   available_daily_budget > 0
              ) ;
    
  2. todays_budgetからすべてをクリアします

    DELETE
    FROM todays_budget ;
    
  3. そして再びそれを埋めます

    INSERT INTO todays_budget
       (campaign_id, original_daily_budget, available_daily_budget)
    SELECT
        campaign_id, 
        CASE WHEN available_budget > daily_budget_limit then
            daily_budget_limit
        ELSE
            available_budget
        END AS original_daily_budget,
        CASE WHEN available_budget > daily_budget_limit then
            daily_budget_limit
        ELSE
            available_budget
        END AS available_daily_budget
    FROM
        budget
    WHERE
        available_budget > 0 ;
    

そして、広告を表示するときはいつでも:available_daily_budgetから1を引いてください

UPDATE 
    todays_budget
SET 
    available_daily_budget = available_daily_budget - 1
WHERE 
    campaign_id = ((the corresponding campaign_id)) ;

メモ

  1. SQLを使用してシナリオを説明しています。 noSQLデータベースでも同じことができます。私はしません。これは、リレーショナルモデルでうまく機能します。
  2. SQLを使用する場合は、手順1〜3をSET ISOLATION LEVEL SERIALIZABLEの下のトランザクションにラップする必要があります。同時実行の問題を回避するため。 チェック制約のいずれかが失敗すると、トランザクション全体が中止され、全体として再試行する必要があります。
  3. 私はできる限りSQL標準を使用しようとしましたが、特定のデータベースでは(わずかに)単純なクエリを使用できます。
  4. 私は、現実的な状況で考慮すべき非常に多くの詳細を無視しています。
2
joanolo