最近、感づいたのが逆正規化の必要性。業務系アプリケーションだとデータ構造の拡張性や上限の無いレコードの管理の必要性から正規化を行うのだが、データ構造は汎用的になる分パフォーマンスが低下すると聞きます。場合によってはリレーションを組んで自動更新・削除した場合は高度なDB設計能力が必要とされます。
で、MMOの場合はどうか。逆にMMOのように莫大な同時接続があってしかも各ユーザー間のデータの同期が必要な場合、クエリー発行のタイムラグがボトルネックになります。MMOの一般常識としてテーブルは非正規化をして効率を上げるらしい。さらにクエリー発行回数を抑えるためMMOサーバー内で保持し続けるのだそうだ。その場合、通信切れはサーバーで感知できるのでデータをDBに保存して終了できるかサーバー自身がダウンしたときDBに保存されないため、一部の巻き戻り現象が起こったりする。
ヘタに自前でメモリ内にデータ保持するより最近のDBの方がサーバープログラミングも確実なんでは?と思うがやはりクエリー発行回数が最終的にネックになる。特に正規化していた場合はSELECT時にJOINを行う為1リクエスト当り若干の速度低下が起こる。しかもそれが蓄積するとあまりよろしくない。さらに問題だと感じたのは正規化した場合の更新と追加は利用するテーブルの数だけクエリーを必要とする。(JOINするテーブルがマスターテーブルの場合はこの限りではない)
そうなると所持アイテム管理等は1アイテム1レコードではなく1キャラ当りの上限を設計の段階で制限して1キャラ1レコードにしないとパフォーマンスに悪影響が出るということでした。現実のテーブル(例えばアイテム欄が100個)でアイテム保障なんてやってられないよなぁ…。
正規化した場合の設計(100種類が上限の場合は1キャラ100レコード)
1.アカウントID(PK)
2.アイテムID(PK)
3.アイテム個数
非正規化した場合
1.アカウントID(PK)
2.アイテム1ID
3.アイテム1個数
|
200.アイテム100ID
201.アイテム100個数
上記のテーブルでアイテム名称を取得する場合特に両者ともJOINするので違いは出てこないが、逆にアイテムの所持状態が変更した場合、正規化テーブルはアイテムの種類ごとにクエリー発行が必要になる。それに対して非正規化テーブルでは一度で済んでしまう。
次に複数テーブルの更新が絡む場合の例としてはゲームキャラの転職等で装備しているアイテムを解除する時など。
正規化テーブル
[アカウントテーブル]
1.アカウントID(PK)
2.職業ID
[装備アイテムテーブル]
1.アカウントID(PK)
2.装備する部位ID(PK)
3.アイテムID
非正規化テーブル
1.アカウントID(PK)
2.職業ID
3.頭装備ID
4.体装備ID
5.右腕装備ID
|
8.靴ID
装備に関しても同じで転職を行ったとき正規化テーブルでは2つのテーブル更新が必要になり(しかも内容がDB設計的には連動しない)最低2回のクエリー実行が必要になるが、非正規化では1回で済む。
データ管理上は大変だが、ここまでパフォーマンス上げないとMMOは成立しない。

コメントする