1 年間の毎日の時間間隔を設定する必要があるキャンペーンがあります。
例えば:
月曜日を除く年中毎日再生され、火曜日の 7 時から 9 時 30 分までは再生されません。
構造を SQL データベースに効果的に格納するにはどうすればよいですか? 365 日と 48 時間の 30 分の間隔があります。非効率的であるため、異なるテーブルへの外部キーを使用したくありません。
ありがとうございました。
1 年間の毎日の時間間隔を設定する必要があるキャンペーンがあります。
例えば:
月曜日を除く年中毎日再生され、火曜日の 7 時から 9 時 30 分までは再生されません。
構造を SQL データベースに効果的に格納するにはどうすればよいですか? 365 日と 48 時間の 30 分の間隔があります。非効率的であるため、異なるテーブルへの外部キーを使用したくありません。
ありがとうございました。
最も単純なテーブルは次のようになります。30 分の時間セグメントの終わりが明示的に格納されていないため、これは最適な構造ではない可能性があります。それにもかかわらず 。. .
create table campaign_times (
campaign_name varchar(35) not null,
time_segment timestamp not null,
play boolean not null default true,
primary key (campaign_name, time_segment)
);
ランダムなキャンペーン名 (約 175 個) を大量に生成し、これらの名前を 1 年間の 30 分間隔 (3,083,520 行) でクロス結合しました。time_segment にインデックスが必要であることはわかっていました。PostgreSQL が使用できる場合に備えて、再生用のインデックスも追加しました。(PostgreSQL は、選択性の低いカラムをインテリジェントに処理することで、過去に何度も驚かされました。)
create index on campaign_times (time_segment);
create index on campaign_times (play);
統計が最新であることを確認してください。
analyze campaign_times;
では、この状況が実際にどれほど悪いか見てみましょう。
explain analyze
select *
from campaign_times
where current_timestamp between time_segment and time_segment + interval '30 minutes'
and play = true;
"Index Scan using campaign_times_time_segment_idx on campaign_times
[snip]
"Total runtime: 498.713 ms"
300 万行のテーブルから現在の再生リストを取得するのに 0.5 秒未満。また、古い行を削除する、より思慮深いインデックスを試す、保存する行数を減らす(今日の日付の 1 か月前など) などの最適化について考える必要もありません。
私はそれで暮らすことができます。
本番環境では、外部キーとチェック制約が必要です。これらは PostgreSQL の SELECT ステートメントの速度には影響しません。また、MySQL の SELECT 速度にも影響しないと思います。(まあ、チェック制約は確かにそうではありません。なぜなら、MySQL はそれらを強制しないからです。)