2012-10-31 3 views
5

Ich habe eine Frage zu SQLAlchemy, Datenbank sharting und UUIDs für Sie feine Leute.SQLAlchemy, UUIDs, Sharding und AUTO_INCREMENT Primärschlüssel ... wie man sie zusammen arbeiten lässt?

ich derzeit MySQL bin mit, in dem habe ich eine Tabelle in der Form:

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

Ein wenig Hintergrund auf dieser Tabelle. Die "added_id" ist mir egal, ich verwende nur, um sicherzustellen, dass die eingefügten Objekte auf dem Datenträger gruppiert sind (da der B-Tree, der zum Indexieren der Tabelle in MySQL verwendet wird, den Primärschlüssel als Cluster-Index verwendet). Die Spalte 'id' enthält die binäre Darstellung einer UUID - das ist die Spalte, die mir wirklich wichtig ist, und alle anderen Dinge verweisen auf diese ID. Wiederum möchte ich nicht, dass die UUID der Primärschlüssel ist, da die UUID zufällig ist und der B-Tree, der zum Indexieren der Tabelle erzeugt wird, schreckliche E/A-Eigenschaften hat (zumindest wurde das an anderer Stelle gesagt). Auch wenn UUID1 den Zeitstempel enthält, um sicherzustellen, dass IDs in "sequenzieller" Reihenfolge generiert werden, ist die Aufnahme der MAC-Adresse in die ID etwas, was ich eher vermeiden möchte. Daher möchte ich UUID4s verwenden.

Ok, jetzt weiter zum SQLAlchemy Teil. oben

# 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) 
    ... 

Auch dies ist im Grunde die gleiche wie die SQL: In SQLAlchemy kann man ein Modell mit ihrem ORM für die obige Tabelle, indem Sie so etwas wie definieren.

Und jetzt zu der Frage. Nehmen wir an, diese Datenbank wird in zwei (oder mehr) separate Datenbanken aufgeteilt (horizontal partitioniert). Nun, (unter der Annahme, dass keine Löschungen vorgenommen wurden), hat jede dieser Datenbanken Datensätze mit added_id von 1, 2, 3 usw. in der Tabelle foo. Da SQLAlchemy eine Sitzung zum Verwalten der Objekte verwendet, an denen gerade gearbeitet wird, so dass jedes Objekt nur durch seinen Primärschlüssel identifiziert wird, scheint es möglich zu sein, dass ich den Versuch beenden könnte, auf zwei Foo-Objekte von beiden zuzugreifen Shards mit derselben added_id führen zu einem Konflikt in der verwalteten Sitzung.

Ist jemand in dieses Problem hineingelaufen? Was hast du getan, um es zu lösen? Oder, mehr als wahrscheinlich, verpasse ich etwas aus der SQLAlchemy-Dokumentation, die sicherstellt, dass dies nicht passieren kann. Betrachtet man jedoch das Sharding-Beispiel, das mit dem SQLAlchemy-Download bereitgestellt wird (examples/sharding/attribute_shard.py), scheinen sie dieses Problem zu umgehen, indem sie einen der Datenbank-Shards als ID-Generator festlegen und so einen impliziten Flaschenhals erzeugen INSERTS müssen gegen diese einzelne Datenbank gehen, um eine ID zu erhalten. (Sie erwähnen auch die Verwendung von UUIDs, aber offenbar verursacht das Leistungsproblem für die Indizes.)

Alternativ gibt es eine Möglichkeit, die UUID als Primärschlüssel festzulegen und die Daten auf der Festplatte mit der added_id gruppiert werden? Wenn es in MySQL nicht möglich ist, ist es in einer anderen DB wie Postgres möglich?

Vielen Dank im Voraus für alle und alle Eingabe!

--- UPDATE ---- Ich möchte nur eine Out-of-Band-Antwort hinzufügen, die ich auf diese Frage erhalten habe. Der folgende Text ist nicht etwas, was ich geschrieben habe, ich möchte es hier nur für den Fall einfügen, dass jemand es nützlich findet.

Der einfachste Weg, um diese Situation mit MySQL und Autoinkrementschlüsseln zu vermeiden, ist die Verwendung verschiedener Autoinkrementoffsets für jede Datenbank, z.:

ALTER TABELLE foo AUTO_INCREMENT = 100000;

Der Nachteil ist, dass Sie darauf achten müssen, wie Sie jeden Shard konfigurieren, und Sie müssen ein bisschen über die Gesamtzahl der verwendeten Shards planen.

Es gibt keine Möglichkeit, MySQL davon zu überzeugen, einen Nicht-Primärschlüssel für den Clustered-Index zu verwenden. Wenn Sie SQLAlchemy nicht zum Verwalten Ihres Datenbankschemas verwenden möchten (obwohl Sie dies wahrscheinlich tun sollten), können Sie die UUID einfach als Primärschlüssel im SQLAlchemy-Schema festlegen und add_id als pk in der tatsächlichen Tabelle belassen.

Ich habe auch alternative Lösungen gesehen, die einfach einen externen Server (z. B. redis) verwenden, um die Zeilen-ID zu pflegen.

Antwort

5

ja, können Sie alle Spalten der Tabelle als Primärschlüssel für die Zwecke der Zuordnung geben Sie das „primary_key“ Mapper Argument, das eine Liste von Column-Objekten oder eine einzelne Spalte ist:

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} 

Oben, während der SQLAlchemy-Kern "add_id" als die "autoincrement" -Spalte behandelt, wird der Mapper daran nicht interessiert sein, sondern "id" als die Spalte verwenden, die bei Berücksichtigung der "Identität" des Objekts wichtig ist .

Siehe die documentation for mapper() für weitere Beschreibung.

+0

Danke eine Million. – prschmid

Verwandte Themen