連載
» 2011年06月23日 00時00分 公開

RDB開発者におくるNoSQLの常識(5):RDBとNoSQLのデータ書き込み法の違い (2/3)

[渡辺俊史,株式会社システムインテグレータ]

「更新」や「削除」をできるだけ避ける

 データに対する4種類のアクセス方法をひとまとめにした「CRUD(クラッド)」という言葉をご存じの方は多いと思います。これはそれぞれCreate(追加)、Read(読み取り)、Update(更新)、Delete(削除)の頭文字を取ったものです。

 このうち、「読み取り」を除いた「追加」「更新」「削除」の3つがデータの書き込み(更新処理)になりますが、複数の更新処理が衝突する(同時実行制御が必要な)書き込み処理は「更新」と「削除」の2つです。

 「追加」は、もともと何もないところへ新たにデータを追加します。キーの一意制約違反といった問題を除けば、並列に処理できます。「更新」と「削除」を避けることで、更新処理を並列化し、処理性能を向上させることができます。言い換えると、更新を並列処理するには、できるだけ更新と削除を避け、追加を主とした更新処理を設計する必要があるのです。

 RDBMSを使っていると、SQLを書くだけで簡単に目的のデータを変更できるので、開発者の中には「UPDATEやDELETEを使わずに更新処理を実現するなんて無理だ」と考える方がいるかもしれません。しかし、「一度登録したものを変更せずに、取り消しや更新を表現する」という考え方自体は特に目新しいものではなく、皆さんの身近なところでも普段からよく使われているのです。

 例えば、業務システム開発者にとって身近な「簿記」のルールはまさに、更新や削除を使わないデータ管理方法であるといえるでしょう。簿記の世界では、お金の出入りをすべて帳簿へ記帳することで管理します。もし記帳した内容に間違いがあったとしても、一度記入した勘定に対して金額を変更することや、記入そのものを取り消すことは一切認められていません。「勘定の変更は不正行為である」というルールがあるからです。

 勘定を訂正する場合は図3のように、必ず反対の意味を持つ勘定を追加して、変更前の勘定を相殺し、それから変更後の新しい勘定を追加します。簿記の世界では勘定に関するイベントをすべて記録しておき、ある時点での値は必要に応じて集計する、という考え方で成り立っています。NoSQLデータベースにもこの考え方を応用できるのです。

図3 更新や削除を使わずにデータを管理する 図3 更新や削除を使わずにデータを管理する

 更新結果を得るには、データ取得時に履歴をすべて集計します。RDBMSであれば集計関数を含んだSELECT文で簡単に集計できますが、NoSQLデータベースの場合は、前回解説した通り、事前にバッチ処理などで生成した集計結果(ある時点のキャッシュ)を読み取ることになります。

複数の更新手順は1アクションにまとめる

 次は、NoSQLデータベースでトランザクションを実現する方法を考えます。冒頭でも述べたように、NoSQLデータベースはRDBMSのようなトランザクション管理機能を持っていません。一部のNoSQLデータベースはトランザクション処理に対応しているようですが、ほとんどは「同一テーブル内のデータを複数件更新する場合のみ」「特定のグループに含まれるテーブルのみ」といった制限がかかっています。ここでは、RDBMSのようなトランザクション管理の仕組みを使用せずに、複数の更新処理を一連の処理として扱う方法を考えます。

 まず、図4のような2つのテーブルTABLE_A、TABLE_Bの更新処理として、RDBMSなら当たり前のトランザクション処理を考えてみます。まずはTABLE_Aに対して更新のSQL(図中の1)を発行します。ここでTABLE_Aの更新データは「保留」の状態になります。それかTABLE_Bにも更新のSQL(図中の2)を発行。TABLE_A、TABLE_Bの更新が両方とも成功したら、最後にCOMMITを実行することで2つの更新処理を同時に確定させることができます。

図4 RDBMSで一般的なトランザクション処理 図4 RDBMSで一般的なトランザクション処理

 TABLE_A、TABLE_Bいずれかの更新処理が失敗したときはROLLBACKを実行することで、両方の更新を同時に取り消すことができます。このトランザクション処理をNoSQLデータベースで実現する方法を考えましょう。

 NoSQLデータベースに対する更新は即時反映され、「保留」にはできません。RDBと同じように2つの更新処理を順番に実行していくと、片方が失敗しても残りの更新処理を取り消すことはできません。さらに、取り消し処理が失敗すると、今度は更新データが中途半端な状態でデータベースに残ってしまいます。

 このような問題を回避するために、NoSQLデータベースではテーブルを1つ1つ更新していくのではなく(図5)のようにトランザクションを記録するためのTABLE_Cを新たに追加し、TABLE_Cにデータを追加することでトランザクションを表現します。「1行分のデータ追加」ですから、更新内容が部分的に適用されることはありません。TABLE_A、TABLE_Bへの反映は非同期処理で、あとで済ませます。

図5 NoSQLデータベースでトランザクション処理を実現する方法 図5 NoSQLデータベースでトランザクション処理を実現する方法

 このように説明すると「データを追加した時点では更新が完了していないじゃないか」と思われる方もいるでしょう。では、少し発想を変えてみましょう。更新処理によって変更されたデータは、いつ必要になるのでしょうか。いつ「更新された」ことが分かるのでしょうか。これまでRDBMSを使っていた人は、トランザクションをCOMMIT(またはROLLBACK)したタイミングでデータベースに対する変更がすべて確定(あるいは取り消し)されるのが当然、と考えていたのではないかと思います。

 しかし、このルールを守っていると、すべての更新処理を矛盾なく取り込むために排他制御が働き、大量の処理待ちが発生してしまいます。データベースに対するすべての更新処理は本当に即時一貫性を保っていなければならないのでしょうか。分散環境での可用性を重視するNoSQLデータベースでは、一貫性の確保を多少犠牲にすることで「更新内容は即時反映されなくとも、実際に読み取られるまでに間に合えばよい」という考え方に切り替えることで、可用性を向上させています。

 図6は、従来の(RDBMS的な)トランザクション処理と、NoSQLデータベースのトランザクション処理の違いを比較したものです。従来のトランザクション処理の特性を表す言葉として「ACID」という言葉があります。これは、トランザクションの4つの特性であるAtomicity(原子性)、Consistency(一貫性)、Isolation(独立性)、Durability(永続性)の頭文字を取ったものです。

図6 ACIDトランザクションとBASEトランザクション 図6 ACIDトランザクションとBASEトランザクション

 一方、NoSQLデータベースのトランザクションの性格は「BASE」という言葉で表すことが多いようです。BASEとは、Basically Available(基本的に利用可能な)/Soft-state(柔らかい状態)/Eventual Consistency(最終的な一貫性)の頭文字を取ったもので、更新前と更新後のデータの間に、どちらの状態でもない不定の時間帯があることを許したトランザクションモデルです。ただし、BASEという言葉の由来としては、トランザクション特性のACIDが「酸」という意味であるのに対してBASE「塩基」という語をあてた駄洒落、という説もあります。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。