1行のログに、何を残すか
このVPSでは、5つのサイト(gwaw / iseeit / appw / ibe / sasagawa)を1台で運用しています。 全サイトのアクセスを1箇所に集めて記録したい——そう考えたとき、最初の問いは 「1アクセスで、何を残すか」でした。
最初に決めたのは4つ。uri(どのページ)、uah(User-Agent)、
addr(IP)、created_at(いつ)。ごく素朴なスタートです。
この時点では、RDB でも MongoDB でも、どちらでも書けます。
203.0.113.x はドキュメント用に予約されたレンジで、実在のアクセス元ではありません。
まず RDB で考えてみる
素直に RDB でテーブルを切るなら、こうなります。
CREATE TABLE access_log ( id BIGINT AUTO_INCREMENT PRIMARY KEY, uri VARCHAR(255), uah VARCHAR(255), addr VARCHAR(45), created_at DATETIME );
RDB の強みははっきりしています。型が保証され、JOIN でき、集計が速い。 ログ用途でも十分に使えます。データの形が変わらなければ、これで何の問題もありません。
問題は、ログというデータが育つことでした。
現実は、フィールドが増えていく
運用を始めると「これも記録したい」が次々と出てきました。実際に後から足したのが2つ。
bot(このアクセスはボットか、という判定フラグ)と、
uqid(同じ訪問者を追うためのセッション識別子)。
どちらも、最初の設計には無かったものです。
ALTER TABLE ... ADD COLUMN でマイグレーション。既存行の扱い、テーブルロック、
5サイト分に膨らんだ行数。「ちょっとフィールドを足す」だけのはずが、本番の大工事になります。
いっぽう MongoDB なら、新しいキーを書き込むだけ。既存のドキュメントはそのまま、
新しく記録するものから bot や uqid が乗ります。
マイグレーションが要らない。ログのように仕様が育つデータと、スキーマレスは相性が抜群でした。
MongoDB のドキュメント
いま、1行のアクセスログは MongoDB でこういう姿をしています。
{
"uri": "/if-sub-260812.html",
"uah": "Mozilla/5.0 ... Chrome/...",
"addr": "203.0.113.42",
"bot": false,
"uqid": "a3f9c1e0-...",
"created_at": ISODate("2026-08-13T05:41:00Z")
}
肝は、フィールドが揃っていなくてもいいことです。
bot や uqid を導入する前に記録した古いドキュメントには、これらのキーがありません。
でも壊れない。「無い=まだその概念が無かった頃のログ」として、新旧が自然に共存します。
型も柔らかい。bot は真偽値、uqid は文字列、created_at は日時。
1つのドキュメントにさまざまな型が同居してよいのです。
固いテーブル vs 柔らかいドキュメント
同じ「bot フィールドを後から足す」という操作を、RDB と MongoDB の両方でやってみます。
同じ操作が、左右でまったく違う重さになります。
RDB は ALTER TABLE で全行に bot=NULL の列が一斉に付き、その間テーブルはロックされます。
MongoDB は新しいドキュメントだけが bot を持ち、既存はそのまま。追記するだけです。
同じ「フィールドを足す」が、片方は大工事・片方はただの追記になります。
スキーマレスは、無秩序ではない
柔らかさには裏返しの代償があります。型が保証されない、表記ゆれが起きうる、 「そのフィールドが無いドキュメント」を常に考慮しないといけない。自由は、放っておくと散らかります。
アプリ側で、書き込む形を統一する
だから最低限の規律を、アプリ側で持ちます。ログを書き込む関数を1つに集約し、
そこで形を揃える。これは TF.js 記事の normalize(データ形状を揃える)と同じ発想です。
スキーマレス=スキーマを考えない、ではありません。DB に強制されない分、アプリで守る。
よく引く軸には、インデックスを張る
スキーマレスでも、検索を速くする仕組みは同じく重要です。created_at(期間で絞る)や
addr(IPで追う)など、よく引く軸にはインデックスを張っておきます。
db.access_log.createIndex({ created_at: -1 }); db.access_log.createIndex({ addr: 1 });
この記事のまとめ
- アクセスログは後から形が育つデータ。
bot・uqidを運用中に追加した。 - RDB の
ALTER TABLEは全行に及ぶ大工事。スキーマレスなら書き込むだけ・マイグレーション不要。 - 1アクセス = 1ドキュメント。フィールドが欠けた古いログとも自然に共存する。
- 代償は「型が保証されない」こと。アプリ側で書き込み形を統一し、よく引く軸にインデックスを張る。