guides/directory-data-model.html

データモデル

6桁規模でディレクトリサイトのスキーマを設計する方法。エンティティ、属性、スラッグ、インデックス、そして複合効果を生む設計の選択肢。

データモデル

← Blog All posts in this topic

複合効果を生むスキーマの決定

28K行(HostList.io)または137K行(Not Another Sunday)のディレクトリサイトは、最初の1週間で下した設計上の決定で成功か失敗かが決まる。最も重要な決定とは、エンティティの正規化方法、属性の保存方法、スラッグの生成方法、何にインデックスを設定するかである。

これらはすべて小規模なら変更可能だが、6桁規模では修正に法外な費用がかかる。最初に正しく設計すること。

エンティティ、属性、ジャンクション

企業、場所、または製品ごとにマスター行を持つ1つのエンティティテーブル。安定したUUID主キー、固有の属性(名前、設立年、主要市場)ごとに1列。この層では属性をJSONカラムに詰め込まないこと。それらは第一級カラムとしてクエリ可能であるべき。

直交軸ごとに1つの属性テーブルを用意する。categories(各行がカテゴリ)、regions(各行がリージョン)、price_tiers(各行がティア)。これらはエンティティがグループ化される次元である。

ジャンクションテーブル経由の多対多リレーションシップ:entity_categories、entity_regions、entity_features。エンティティテーブルにカンマ区切りのカテゴリリストを保存しないこと。ジャンクションテーブルがあるからこそ、フィルタリング、リスティング、カウントが高速になる。

スラッグは永遠

ディレクトリページがGoogleにインデックスされたら、スラッグを変更してはいけない。エンティティ名から決定論的にスラッグを生成し、衝突時は数値サフィックスで対応する:nginx-hosting、衝突した場合はnginx-hosting-2。

過去のスラッグをすべて現在の正規スラッグにマッピングする別の slug_history テーブルを保持する。エンティティ名の変更が必要な場合(修正、ブランド変更)、新しい正規スラッグを生成し、古いスラッグをhistoryテーブルに入れ、永続的な301リダイレクトを自動的にセットアップする。

28K行のサイトでスラッグの安定性を誤ると、その代償は甚大だ:作成するリダイレクトチェーンが1つ増えるたびにランキング低下が起き、事後的な対処法はない。

行レベルでのインデックス可能性

エンティティテーブルに indexable ブール値カラムを追加し、デフォルトは true とする。エンティティが品質閾値を満たさない場合(独自コンテンツが不足、必須属性が欠落、内部リンクがない)、このカラムは false に切り替わる。

サイトマップクエリは indexable = true でフィルタリングする。ページレンダラーは indexable = false のときに noindex メタを追加する。どちらも同じカラムから派生しているため、アトミックに同期が保たれる。

HostList.io では、任意の時点で28K中およそ18KのエンティティがインデックスPossible状態にある。残りの10Kはクロール可能だがインデックス不可で、これでインデックス対象の表面を清潔に保ち、インデックス済みページ全体を強化する。

重要なインデックス

ページレンダリング検索用のslugインデックス。サイトマップクエリ用の(indexable, last_updated_at)インデックス。カテゴリーリスティングページ用のジャンクションテーブルの(category_id, indexable)インデックス。地域別ページ用の(region_id, indexable)インデックス。

6桁の行数規模では、インデックスなしのページレンダリングクエリは数秒かかる。適切なインデックスがあれば、ミリ秒単位で済む。ビルド時間への影響は複合的に生じる:28Kページレンダリングを1つあたり100msで実行すると47分、1つあたり10msなら5分だ。

スケール時のページレンダリングクエリすべてに対してEXPLAIN ANALYZEを実行する。デフォルトのクエリプランナーは、ディレクトリ構造のジョインではあなたが予想するより頻繁に誤った判断をする。

WHEN YOU ARE READY TO TALK