シナリオ:各ユーザーは自分のアカウントに資金(たとえば100 USD)を追加し、システム(私たちのWebサイト)は自分の広告をWebサイトに表示するために1日あたり最大10 USDを費やすことができると定義しています。または広告がウェブサイトに表示されるたびに、1米ドルの費用がかかります。
PS:広告が表示されるたびにレコードをデータベースに挿入するのではなく、広告を表示するための金額(1 USD
)だけをdeduct
予算。
表示する広告が多すぎるため、各広告ショーのレコードをデータベースに挿入することはできません。
Usersテーブルにはwhole_budget
とdaily_budget
の2つの列があるため、上記のユーザーの場合、whole_budget
は100
で、daily_budget
は10
です。
上記のシナリオでは、daily budget
をどのように管理できますか?広告が表示されたら、彼のアカウントから1 USDをどのように差し引くのでしょうか。
彼が1日の予算を残したかどうかをどのように知ることができますか?その日の残りの時間に彼の広告を表示するかどうかを決めることができます。
よろしくお願いします
編集---------------
これは、shown_ads
というテーブルを作成することで簡単に実現できます。広告を表示するたびに、尊重されたDATE()を使用してこのテーブルにレコードを挿入し、後で彼がすでに費やした彼の予算額を計算できるようにします今日。しかし、毎日1M
広告を表示しているとしましょう。私が信じていることは、毎日100万件のレコードを挿入するのはよくないことです!これは単なるケーススタディです。これをどのように実装するか知りたいです。
(おそらく)最も簡単な解決策は次のとおりです。
各キャンペーンの予算全体について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に、次の操作を実行します。
budget
からspent_budget
(original_daily_budget - available_daily_budget
)を減算しますDELETE
todays_budget
のすべてINSERT
todays_budget
への新しい行。original_dailyとavailable_dailyの両方の予算は、(daily_budget_limit、available_budget)の最小値に等しいこれは、次のクエリで実行できます。
昨日から残りを引く
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
) ;
todays_budgetからすべてをクリアします
DELETE
FROM todays_budget ;
そして再びそれを埋めます
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)) ;
メモ
SET ISOLATION LEVEL SERIALIZABLE
の下のトランザクションにラップする必要があります。同時実行の問題を回避するため。 チェック制約のいずれかが失敗すると、トランザクション全体が中止され、全体として再試行する必要があります。