LoginSignup
7
1

More than 1 year has passed since last update.

export 7.png

Identity Map は、同じ行に対応するデータオブジェクトの重複生成を避けるためのパターンです。

SQL によるクエリの評価結果は、行そのものではなく、あくまでその時点でのスナップショットコピーにすぎません。同じ問い合わせを繰り返すと、いくらでも同じものが出てきます。また、同じ SQL 文でも、タイミングが違えば、同一実体だと思っていたものの内容が異なるインスタンスが生まれるかもしれません。

責務分担の複雑な Domain Model では、そのような現象が多発します。取得してメモリ上でデータ内容を変更したあと、それを書き戻すまでに呼び出した別の処理によって、未保存のデータが再取得され、データベースを書き換えていた、といった事故が起きる可能性もあります (しつこいようですが、手続きの詳細をすべて掌握するのは Transaction Script です)。そのため、単純な Active Record が Domain Model として有利になってくるのは、実は、思いのほか短い処理で済む場合だけになってきます。

メモリ上にデータベースをミラーリングするスペースを設け、同じ行に対応するインスタンスは常にひとつになる仕組みを作ると、本物がどれだかわからなくなる問題を解消できます。主キーはユニークで行を一意特定できるので、これを利用すれば、簡単にインデックスを付けることができます。

エンティティの一意性は、Unit Of Work にとって絶対に欠かせない、重要な特性です。Unit Of Work によってトランザクション最適化をする Data Mapper は、必ず Identity Map を持つ必要があります。

Identity Map を設けることで、論理矛盾以外のメリットも得ることができます。複雑なデータ構造の大幅なメモリ節約の効果です。

ある行の集合の各要素について、関連する行を追跡して取得すると、その中には重複するものも出てきます。通常、本の著者は複数の本を執筆しています。愚直に本を起点に関連を辿ると、同じ著者に異なる複数のインスタンスができます。それだけならまだ良いのですが、さらに著者が持つ属性を辿り、その各属性の種別を辿り、と、何層もの構造を読んでいくとどうなるでしょう。データベーステーブルにはユニークな行が 100 ほどしかないのに、メモリ上には何千何万のオブジェクトインスタンスが発生するかもしれません (冗談ではなく本当になります)。そうした重複行を取得するクエリを都度発行するのは、通信量にもデータベースの CPU にも迷惑です。

Identity Map を利用すれば、過去にすでにインスタンス化を済ませたオブジェクトを再利用できます。深い構造を辿った結果を残してあれば、その再取得にかかるコストをいっさい払わなくて済みます。Identity Map 内のインスタンス数は、絶対に、テーブルに実在する行の数を超えません。

情報を要約した Web ページにちょっと付加情報を足そうとしただけで、裏に数千ものクエリが増えてパフォーマンスを劇的に悪化させてしまう現象は、本当によくあります。Data Mapper が目的でなくとも、俗に言われる N + 1 問題を回避するひとつの策として、Identity Map のアイデアは有効です(個別の Lazy Load を繰り返すのではなく一括で Eager Load にするといった方法とはまた別のアプローチとして)。

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1