視聴されている動画に関する統計を多数保持する必要があります。そのうちの 1 つは、動画のどの部分が最も視聴されているかです。私が思いついた設計は、ビデオを 256 の間隔に分割し、それぞれのビューの浮動小数点数を保持することです。ユーザーが連続して見た間隔の数としてデータを受け取ります。問題は、それらをどのように保管するかです。私が見る2つの解決策があります。
動画セグメントごとの行
次のようなデータベーステーブルを用意しましょう。
CREATE TABLE `video_heatmap` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`video_id` int(11) NOT NULL,
`position` tinyint(3) unsigned NOT NULL,
`views` float NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_lookup` (`video_id`,`position`)
) ENGINE=MyISAM
次に、多数のビューを処理する必要があるときはいつでも、それぞれのデータベース行があることを確認し、適切な値を列に追加しviews
ます。SELECT COUNT(*)
行の存在が最初に処理されると(特定のビデオの行と行INSERT IGNORE
が不足している場合)、次のようにいくつかの更新クエリが使用されると、はるかに高速になることがわかりました。
UPDATE video_heatmap
SET views = views + ?
WHERE video_id = ? AND position >= ? AND position < ?
ただし、これは少し膨らんでいるようです。私が思いついた他の解決策は
動画ごとに行、トランザクションで更新
テーブルは次のようになります。
CREATE TABLE video (
id INT NOT NULL AUTO_INCREMENT,
heatmap BINARY (4 * 256) NOT NULL,
...
) ENGINE=InnoDB
次に、ビューを保存する必要があるたびに、次のような順序で、一貫性のあるスナップショットを使用してトランザクションで実行されます。
- ビデオがデータベースに存在しない場合は、作成されます。
- バイナリ形式で格納された float の配列である行が取得
heatmap
され、(PHP で) より処理しやすい形式に変換されます。 - 配列内の値が適切に増加され、配列が変換されます。
- 行は
UPDATE
クエリによって変更されます。
これまでのところ、利点は次のように要約できます。
最初のアプローチ
- データを魔法のバイナリ配列としてではなく、float として格納します。
- トランザクション サポートを必要としないため、InnoDB は必要ありません。また、現時点ではすべてに MyISAM を使用しているため、ストレージ エンジンを混在させる必要はありません。(私の特定の状況にのみ適用されます)
- トランザクションを必要としません
WITH CONSISTENT SNAPSHOT
。それらのパフォーマンスのペナルティが何であるかはわかりません。 - 私はすでにそれを実装しており、動作します。(私の特定の状況にのみ適用されます)
2 番目のアプローチ
- 使用するストレージ スペースが大幅に削減されます (最初のアプローチでは、ビデオ ID を 256 回保存し、ビデオのすべてのセグメントの位置を保存します。プライマリ キーは言うまでもありません)。
- MyISAM のテーブル ロックとは対照的に、InnoDB の行ごとのロックにより、より適切にスケーリングする必要があります。
- 行われるリクエストがはるかに少ないため、通常はより速く動作する可能性があります。
- コードで実装する方が簡単です(ただし、もう一方は既に実装されています)。
それで、私は何をすべきですか?MyISAM を一貫して使用するシステムの残りの部分がなければ、2 番目のアプローチを使用しますが、現在は最初のアプローチに傾いています。しかし、どちらかのアプローチを支持する理由がいくつかあるのではないでしょうか?