web-dev-qa-db-ja.com

データベースの代わりにデータストアで考える方法

例として、Google App Engineは標準のデータベースではなく、Google Datastoreを使用してデータを保存します。データベースの代わりにGoogle Datastoreを使用するためのヒントはありますか?テーブル構造に直接マッピングされるオブジェクトリレーションシップを100%考えるように心を鍛えたように思えますが、今では何かを見るのは難しいです。 Google Datastoreの利点の一部(たとえば、パフォーマンスとデータを配布する機能)は理解できますが、優れたデータベース機能は犠牲になります(結合など)。

Google DatastoreまたはBigTableを使用したことがある人は、彼らと一緒に作業するための良いアドバイスがありますか?

181
Jim

「従来の」リレーショナルデータベースと比較した場合、App Engineデータストアに慣れるには、主に2つのことがあります。

  • データストアは、挿入と更新を区別しません。エンティティでput()を呼び出すと、そのエンティティは一意のキーでデータストアに保存され、そのキーを持つものはすべて上書きされます。基本的に、データストア内の各エンティティの種類は、巨大なマップまたはソートされたリストのように機能します。
  • あなたが示唆したように、クエリははるかに制限されています。最初は参加しません。

実現する重要なことと、これらの違いの背後にある理由は、Bigtableが基本的に巨大な順序付けられた辞書のように振る舞うことです。したがって、put操作は特定のキーの値を設定するだけです。そのキーの以前の値に関係なく、フェッチ操作は単一のキーまたは連続したキーの範囲のフェッチに制限されます。基本的に独自のテーブルであるインデックスを使用すると、より高度なクエリが可能になり、より複雑なクエリを連続した範囲でのスキャンとして実装できます。

それを吸収したら、データストアの機能と制限を理解するために必要な基本的な知識が得られます。 arbitrary意的に見えるかもしれない制限は、おそらくより理にかなっています。

ここで重要なことは、これらはリレーショナルデータベースで実行できることに対する制限ですが、これらの同じ制限が、Bigtableが処理するように設計された規模にまでスケールアップすることを実用的にすることです。紙上では良さそうに見えても、SQLデータベースではひどく遅い種類のクエリを実行することはできません。

データの表現方法を変更する方法に関して、最も重要なことは事前計算です。クエリ時に結合を行う代わりに、データを事前に計算し、可能な限りデータストアに保存します。ランダムなレコードを選択する場合は、乱数を生成して各レコードに保存します。 これらの種類のヒントとトリックのクックブックがあります ここ 編集:クックブックは存在しなくなりました。

148
Nick Johnson

私がマインドスイッチについて行ってきた方法は、データベースを完全に忘れることです。

リレーショナルデータベースの世界では、データの正規化とテーブル構造について常に心配する必要があります。それをすべて捨てる。 Webページをレイアウトするだけです。それらをすべてレイアウトします。今それらを見てください。すでに2/3です。

データベースのサイズが重要であり、データを複製してはならないという概念を忘れた場合、3/4になり、コードを記述する必要さえありません。ビューでモデルを決定してください。リレーショナルの世界のように、オブジェクトを2次元にする必要はもうありません。形状のあるオブジェクトを保存できるようになりました。

はい、これは試練の簡単な説明ですが、データベースを忘れてアプリケーションを作成するのに役立ちました。この哲学を使用して、これまでに4つのApp Engineアプリを作成しましたが、まだまだあります。

41
user19087

人々が出てくるとき、私はいつもくすくす笑います-それはリレーショナルではありません。私はcellectrをDjangoで記述しました。以下に私のモデルの抜粋を示します。ご覧のように、ユーザーが管理または指導しているリーグがあります。マネージャー、または特定のユーザーから、コーチやマネージャーのリーグを返すことができます。

特定の外部キーがサポートされていないからといって、リレーションシップを持つデータベースモデルを作成できないわけではありません。

私の2ペンス。


class League(BaseModel):
    name = db.StringProperty()    
    managers = db.ListProperty(db.Key) #all the users who can view/edit this league
    coaches = db.ListProperty(db.Key) #all the users who are able to view this league

    def get_managers(self):
        # This returns the models themselves, not just the keys that are stored in teams
        return UserPrefs.get(self.managers)

    def get_coaches(self):
        # This returns the models themselves, not just the keys that are stored in teams
        return UserPrefs.get(self.coaches)      

    def __str__(self):
        return self.name

    # Need to delete all the associated games, teams and players
    def delete(self):
        for player in self.leagues_players:
            player.delete()
        for game in self.leagues_games:
            game.delete()
        for team in self.leagues_teams:
            team.delete()            
        super(League, self).delete()

class UserPrefs(db.Model):
    user = db.UserProperty()
    league_ref = db.ReferenceProperty(reference_class=League,
                            collection_name='users') #league the users are managing

    def __str__(self):
        return self.user.nickname

    # many-to-many relationship, a user can coach many leagues, a league can be
    # coached by many users
    @property
    def managing(self):
        return League.gql('WHERE managers = :1', self.key())

    @property
    def coaching(self):
        return League.gql('WHERE coaches = :1', self.key())

    # remove all references to me when I'm deleted
    def delete(self):
        for manager in self.managing:
            manager.managers.remove(self.key())
            manager.put()
        for coach in self.managing:
            coach.coaches.remove(self.key())
            coaches.put()            
        super(UserPrefs, self).delete()    
23
Phil Stollery

リレーショナルデータベースの世界から来て、このデータストアを見つけました。ハングアップするのに数日かかりました。まあ私の調査結果のいくつかがあります。

Datastoreはスケールに合わせて構築されていることを既に知っている必要があり、それがRDMBSからデータストアを分離するものです。大規模なデータセットでより適切にスケーリングするために、App Engineはいくつかの変更を行いました(いくつかは多くの変更を意味します)。

RDBMS VS DataStore
構造
データベースでは、通常、データストア内にあるテーブル、行のデータを構造化します Kinds and Entities

関係
RDBMSでは、ほとんどの人が1対1、多対1、多対多の関係をフォローします。データストアでは、「結合なし」というものがありますが、 「ReferenceProperty」を使用した正規化 1対1の関係の例

インデックス
通常RDMBSでは、検索を高速化し、データベースのパフォーマンスを向上させるために、プライマリキー、外部キー、一意キー、インデックスキーなどのインデックスを作成します。データストアでは、データストアがこれらのインデックスに基づいてエンティティを検索し、それが最良の部分であると信じているため、種類ごとに少なくとも1つのインデックスを作成する必要があります(自動的に 生成 好きかどうかにかかわらず) 、RDBMSでは、非インデックスフィールドを使用して検索できますが、時間がかかりますが、時間がかかります。データストアでは、インデックス以外のプロパティを使用して検索することはできません。

カウント
RDMBSでは、count(*)の方がはるかに簡単ですが、データストアでは、 1000 Limit があり、通常の方法(カウント機能がある)でさえ考えないでください。 small opertion 良くないエンティティと同じくらいのコストがかかりますが、常に良い選択肢があります Shard Counters を使用できます。

一意の制約
RDMBSでは、この機能が気に入っていますか?しかし、データストアには独自の方法があります。プロパティを一意の:(として定義することはできません。

クエリ
GAE Datatoreはより優れた機能を提供します [〜#〜] like [〜#〜] (Oh no!データストアにはLIKEキーワードがありません)SQLである [〜 #〜] gql [〜#〜]

データの挿入/更新/削除/選択
これはRDBMSのように、RDBMSのように挿入、更新、削除、選択のクエリを1つ必要とします。 書き込み、読み取り、小規模操作 (読み取りデータストアコールのコスト)、およびデータモデリングが実行される場所についてこれらの操作を最小限に抑え、アプリを実行し続ける必要があります。 読み取り操作 を削減するには、 Memcache を使用できます。

12
sanjay kushwah

Objectifyのドキュメントをご覧ください。ページ下部の最初のコメントは次のとおりです。

「素晴らしい、Objectifyを説明するためにこれを書いたが、これは私が今まで読んだappengineデータストア自体の最も簡潔な説明の1つでもある。ありがとう。」

https://github.com/objectify/objectify/wiki/Concepts

6
Jon Stevens

ORMにマップされたエンティティについて考えることに慣れている場合、それは基本的にGoogleのApp Engineのようなエンティティベースのデータストアの仕組みです。結合のようなものについては、 参照プロパティ をご覧ください。バックエンドはGQLとデータストアAPIインターフェースによって抽象化されるため、バックエンドにBigTableを使用するか、他の何かに使用するかを実際に心配する必要はありません。

3
Mark Cidade

データストアを見ると、種類はそれ自体がテーブルを識別し、エンティティはテーブル内の個々の行です。 googleが構造のない1つの大きなテーブルよりも親切になり、エンティティに必要なものをダンプできる場合。言い換えれば、エンティティが種類に結び付けられていない場合、エンティティに任意の構造を持ち、1つの場所に格納できます(構造のない大きなファイルのようなもので、各行には独自の構造があります)。

元のコメントに戻りますが、Googleデータストアとbigtableは2つの異なるものであるため、Googleデータストアとデータストアデータストレージの意味を混同しないでください。 Bigtableは、bigqueryよりも高価です(これを使用しなかった主な理由)。 Bigqueryには適切な結合とRDBMSがあり、SQL言語のように安価であり、bigqueryを使用しないのはなぜですか。とはいえ、bigqueryには、遭遇する可能性のあるデータサイズと遭遇しないデータのサイズに応じて、いくつかの制限があります。

また、データストアの観点から考えると、適切なステートメントは「NoSQLデータベースの観点から考える」ことになると思います。最近利用できるものは多すぎますが、Google Cloud SQL(mySQL)以外のGoogle製品に関しては、他のすべてはNoSQLです。

0
ringadingding