5

SQLAlchemy、データベース シャーディング、UUID について質問があります。

現在、次の形式のテーブルがある MySQL を使用しています。

CREATE TABLE foo (
    added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    id BINARY(16) NOT NULL,
    ... other stuff ...
    UNIQUE KEY(id)
);

このテーブルの背景を少し。「added_id」は気にしません。挿入されたアイテムがディスク上でクラスター化されていることを確認するためだけに使用しています (MySQL でテーブルをインデックス化するために使用される B ツリーは、主キーをクラスター インデックスとして使用するため)。「id」列には、UUID のバイナリ表現が含まれています。これは私が実際に気にかけている列であり、他のすべてのものはこの ID を参照しています。繰り返しますが、UUID はランダムであり、テーブルのインデックスを作成するために作成された B ツリーが恐ろしい IO 特性を持つようになるため、UUID を主キーにしたくありません (少なくともそれは他の場所で言われていることです)。また、UUID1 には ID が「連続した」順序で生成されるようにするためのタイムスタンプが含まれていますが、ID に MAC アドレスが含まれていると、むしろ避けたいものになります。したがって、UUID4 を使用したいと思います。

さて、SQLAlchemy の部分に移ります。SQLAlchemy では、次のようにして、上記のテーブルの ORM を使用してモデルを定義できます。

# The SQL Alchemy ORM base class
Base = declerative_base()

# The model for table 'foo'
class Foo(Base):
    __table__ = 'foo'
    add_id = Column(Integer, primary_key=True, nullable=False)
    id = Column(Binary, index=True, unique=True, nullable=False)
    ...

繰り返しますが、これは基本的に上記の SQL と同じです。

そして今、質問に。このデータベースが 2 つ (またはそれ以上) の別個のデータベースに分割 (水平分割) されるとします。ここで、(削除がないと仮定して) これらのデータベースのそれぞれは、テーブル foo に 1、2、3 などの added_id を持つレコードを持ちます。SQLAlchemy はセッションを使用して、各オブジェクトが主キーのみで識別されるように、作業中のオブジェクトを管理するため、2 つの Foo オブジェクトから 2 つの Foo オブジェクトにアクセスしようとして終了する可能性があるようです。同じ added_id を持つシャードは、管理されたセッションで競合を引き起こします。

誰かがこの問題に遭遇しましたか? それを解決するために何をしましたか?または、おそらく、これが起こらないことを保証する SQLAlchemy のドキュメントから何かが欠けています。ただし、SQLAlchemy のダウンロード (examples/sharding/attribute_shard.py) で提供されるシャーディングの例を見ると、データベース シャードの 1 つを ID ジェネレーターとして指定することで、この問題を回避しているように見えます。 INSERTS は、ID を取得するためにその単一のデータベースに対して実行する必要があります。(彼らは UUID の使用についても言及していますが、明らかにインデックスのパフォーマンスの問題を引き起こします。)

または、UUID を主キーとして設定し、added_id を使用してデータをディスク上にクラスター化する方法はありますか? MySQL で不可能な場合、Postgres のような別の DB で可能ですか?

あらゆるご意見をお寄せいただきありがとうございます。

--- 更新 ---- この質問に対して受け取った範囲外の回答を追加したいだけです。次のテキストは私が書いたものではありません。誰かが役に立つと思った場合に備えて、ここに含めたいと思います.

MySQL と自動インクリメント キーでこの状況を回避する最も簡単な方法は、データベースごとに異なる自動インクリメント オフセットを使用することです。次に例を示します。

ALTER TABLE foo AUTO_INCREMENT=100000;

欠点は、各シャードの構成方法に注意する必要があり、使用するシャードの総数について少し計画する必要があることです。

クラスター化インデックスに非主キーを使用するように MySQL を説得する方法はありません。SQLAlchemy を使用してデータベース スキーマを管理することを気にしない場合 (おそらく使用する必要があります)、単純に UUID を SQLAlchemy スキーマの主キーとして設定し、add_id を実際のテーブルの pk のままにしておくことができます。

また、単純に外部サーバー (redis など) を使用して行 ID を維持する代替ソリューションも見てきました。

4

1 に答える 1

5

はい、「primary_key」マッパー引数を使用して、マッピングの目的でテーブルの任意の列を主キーとして指定できます。これは、列オブジェクトのリストまたは単一の列です。

Base = declarative_base()

# The model for table 'foo'
class Foo(Base):
    __table__ = 'foo'
    add_id = Column(Integer, primary_key=True, nullable=False)
    id = Column(Binary, index=True, unique=True, nullable=False)

    __mapper_args__ = {'primary_key': id}

上記では、SQLAlchemy コアは「add_id」を「autoincrement」列として扱いますが、マッパーはほとんど関心がなく、オブジェクトの「ID」を考慮するときに、「id」を列として使用します。

詳細については、 mapper() のドキュメントを参照してください。

于 2012-11-06T22:31:29.507 に答える