質問

単純な正規化されたデータベースを持つWebサイトで作業しています。

PagesというテーブルとViewsというテーブルがあります。ページが表示されるたびに、そのビューの一意のレコードがビューテーブルに記録されます。

サイトにページを表示するとき、表示するビューの数を合計するために単純なMySQL COUNT()を使用します。

この問題を除いて、データベースの設計は問題ないように見えます。数千の中で最も多く表示されているトップ10のページを取得する方法がわかりません。

Pages.views列を追加して、各ページの合計ビュー数を保持することにより、Pagesテーブルを非正規化する必要がありますか?または、最も閲覧された上位10ページを照会する効率的な方法はありますか?

役に立ちましたか?

解決

   SELECT p.pageid, count(*) as viewcount FROM 
   pages p
   inner join views v on p.pageid = v.pageid
   group by p.pageid
   order by count(*) desc   
   LIMIT 10 OFFSET 0;

これをテストすることはできませんが、それらの線に沿って何かをテストします。パフォーマンスの制約のために必要な場合を除き、値を保存しません(「時期尚早な最適化」という用語を学習しましたが、そうする場合に適用されるようです)。

他のヒント

これは、維持しようとしている情報のレベルによって異なります。誰がいつ視聴したかを記録したい場合は?その後、別のテーブルで問題ありません。それ以外の場合は、ビューの列を使用する方法です。また、別の列を保持すると、各ページビューが対応する行の列を更新しようとするため、テーブルがより頻繁にロックされることがわかります。

Select pageid, Count(*) as countCol from Views
group by pageid order by countCol DESC
LIMIT 10 OFFSET 0;

おそらく、ページテーブルにビュー列を含めます。

これは、正規化を完全に合理的に破ったように思えます。特に、あなたがビューを削除することを想像できないので、カウントが強打から抜け出すことを期待しないでしょう。この場合、参照整合性は超クリティカルではないようです。

データベースの正規化は、データを保存するための最も効率的で冗長性の少ない方法に関するものです。これはトランザクション処理には適していますが、多くの場合、データを再び効率的に取り出す必要性と直接競合します。この問題は通常、よりアクセスしやすく前処理されたデータを持つ派生テーブル(インデックス、マテリアライズドビュー、ロールアップテーブルなど)を使用することで解決されます。ここでの(少し古い)流行語はデータウェアハウジングです。

Pagesテーブルを正規化したままにしたいが、合計を含む追加のテーブルが必要だと思います。これらのカウントを最新にする必要性に応じて、元のテーブルを更新するときにテーブルを更新するか、バックグラウンドジョブを使用して定期的に合計を再計算できます。

これは、実際にパフォーマンスの問題が発生した場合にのみ行います。これは、非常に多くのレコードまたは非常に多くの同時アクセスがない限り起こりません。テーブルの有無を切り替えられるように、コードを柔軟に保ちます。

この場合、非正規化は間違いなく機能します。あなたの損失は、余分な列によって使い果たされた余分な保管室です。

別の方法として、スケジュールされたジョブを設定して、トラフィックが少ないx期間、夜間にこの情報を入力することもできます。

この場合、このクエリを手動で実行しない限り、ページ数を即座に知ることができなくなります。

非正規化は間違いなくパフォーマンスを向上させるために使用できます。

-クリス

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top