Index mehrerer Spalten bei Verwendung der deklarativen ORM-Erweiterung von sqlalchemy

94

Gemäß der Dokumentation und den Kommentaren in der sqlalchemy.ColumnKlasse sollten wir die Klasse verwenden sqlalchemy.schema.Index, um einen Index anzugeben, der mehrere Spalten enthält.

Das Beispiel zeigt jedoch, wie dies direkt mit dem Table-Objekt geschieht:

meta = MetaData()
mytable = Table('mytable', meta,
    # an indexed column, with index "ix_mytable_col1"
    Column('col1', Integer, index=True),

    # a uniquely indexed column with index "ix_mytable_col2"
    Column('col2', Integer, index=True, unique=True),

    Column('col3', Integer),
    Column('col4', Integer),

    Column('col5', Integer),
    Column('col6', Integer),
    )

# place an index on col3, col4
Index('idx_col34', mytable.c.col3, mytable.c.col4)

Wie sollen wir es machen, wenn wir die deklarative ORM-Erweiterung verwenden?

class A(Base):
    __tablename__ = 'table_A'
    id = Column(Integer, , primary_key=True)
    a = Column(String(32))
    b = Column(String(32))

Ich möchte einen Index für die Spalten "a" und "b".

yorjo
quelle
1
Die Frage ist etwas unklar, ob Sie mehrere Indizes oder einen einzelnen Index für mehrere Spalten möchten (und war verwirrter, bevor ich ihn bearbeitet habe - ursprünglich wurde erfreulicherweise nach "einem Index gefragt , der mehrere mehrere Indizes enthält" ). Aber egal, denke ich, da die Antwort von zzzeek beide Fälle anspricht.
Mark Amery

Antworten:

137

das sind nur ColumnObjekte, index = True Flag funktioniert normal:

class A(Base):
    __tablename__ = 'table_A'
    id = Column(Integer, primary_key=True)
    a = Column(String(32), index=True)
    b = Column(String(32), index=True)

Wenn Sie einen zusammengesetzten Index möchten, der Tablehier wie gewohnt wieder vorhanden ist, müssen Sie ihn einfach nicht deklarieren. Alles funktioniert gleich (stellen Sie sicher, dass Sie den aktuellen Wert von 0,6 oder 0,7 haben, damit der deklarative Aa-Wrapper als interpretiert wird Columnnach Abschluss der Klassendeklaration):

class A(Base):
    __tablename__ = 'table_A'
    id = Column(Integer, primary_key=True)
    a = Column(String(32))
    b = Column(String(32))

Index('my_index', A.a, A.b)

In 0.7 Indexkann das auch in den TableArgumenten sein, was mit deklarativ via ist __table_args__:

class A(Base):
    __tablename__ = 'table_A'
    id = Column(Integer, primary_key=True)
    a = Column(String(32))
    b = Column(String(32))
    __table_args__ = (Index('my_index', "a", "b"), )
zzzeek
quelle
1
Danke, ich habe auf 0.7 aktualisiert und die Verwendung von table_args funktioniert
einwandfrei
5
Was passiert, wenn Sie ein Wörterbuch für table_args haben, wie ich es derzeit tue? table_args = {'mysql_engine': 'InnoDB'}
Nick Holden
6
Ich denke also, ich kann table_args = (Index ('my_index', "a", "b"), {'mysql_engine': 'InnoDB'}) ausführen
Nick Holden
1
@ RyanChou docs.sqlalchemy.org/en/latest/orm/extensions/declarative/… "Schlüsselwortargumente können mit dem obigen Formular angegeben werden, indem das letzte Argument als Wörterbuch angegeben wird"
zzzeek
12

Um die Antwort von @ zzzeek zu vervollständigen .

Wenn Sie mit DESC einen zusammengesetzten Index hinzufügen und die deklarative ORM-Methode verwenden möchten, können Sie wie folgt vorgehen.

Außerdem hatte ich Probleme mit der Dokumentation der Funktionsindizes von SQSAlchemy und versuchte herauszufinden, wie ich sie ersetzen kann mytable.c.somecol.

from sqlalchemy import Index

Index('someindex', mytable.c.somecol.desc())

Wir können einfach die Modelleigenschaft verwenden und sie aufrufen .desc():

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class GpsReport(db.Model):
    __tablename__ = 'gps_report'

    id = db.Column(db.Integer, db.Sequence('gps_report_id_seq'), nullable=False, autoincrement=True, server_default=db.text("nextval('gps_report_id_seq'::regclass)"))

    timestamp = db.Column(db.DateTime, nullable=False, primary_key=True)

    device_id = db.Column(db.Integer, db.ForeignKey('device.id'), primary_key=True, autoincrement=False)
    device = db.relationship("Device", back_populates="gps_reports")


    # Indexes

    __table_args__ = (
        db.Index('gps_report_timestamp_device_id_idx', timestamp.desc(), device_id),
    )

Wenn Sie Alembic verwenden, verwende ich Flask-Migrate. Es generiert Folgendes:

from alembic import op  
import sqlalchemy as sa
# Added manually this import
from sqlalchemy.schema import Sequence, CreateSequence


def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    # Manually added the Sequence creation
    op.execute(CreateSequence(Sequence('gps_report_id_seq')))

    op.create_table('gps_report',
    sa.Column('id', sa.Integer(), server_default=sa.text("nextval('gps_report_id_seq'::regclass)"), nullable=False),
    sa.Column('timestamp', sa.DateTime(), nullable=False))
    sa.Column('device_id', sa.Integer(), autoincrement=False, nullable=False),
    op.create_index('gps_report_timestamp_device_id_idx', 'gps_report', [sa.text('timestamp DESC'), 'device_id'], unique=False)


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_index('gps_report_timestamp_device_id_idx', table_name='gps_report')
    op.drop_table('gps_report')

    # Manually added the Sequence removal
    op.execute(sa.schema.DropSequence(sa.Sequence('gps_report_id_seq'))) 
    # ### end Alembic commands ###

Schließlich sollten Sie die folgende Tabelle und Indizes in Ihrer PostgreSQL-Datenbank haben:

psql> \d gps_report;
                                           Table "public.gps_report"
     Column      |            Type             | Collation | Nullable |                Default                 
-----------------+-----------------------------+-----------+----------+----------------------------------------
 id              | integer                     |           | not null | nextval('gps_report_id_seq'::regclass)
 timestamp       | timestamp without time zone |           | not null | 
 device_id       | integer                     |           | not null | 
Indexes:
    "gps_report_pkey" PRIMARY KEY, btree ("timestamp", device_id)
    "gps_report_timestamp_device_id_idx" btree ("timestamp" DESC, device_id)
Foreign-key constraints:
    "gps_report_device_id_fkey" FOREIGN KEY (device_id) REFERENCES device(id)
Mickael
quelle