Indeks beberapa kolom saat menggunakan ekstensi ORM deklaratif dari sqlalchemy

97

Menurut dokumentasi dan komentar di sqlalchemy.Columnkelas, kita harus menggunakan kelas sqlalchemy.schema.Indexuntuk menentukan indeks yang berisi banyak kolom.

Namun, contoh tersebut menunjukkan bagaimana melakukannya dengan langsung menggunakan objek Tabel seperti ini:

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)

Bagaimana kita melakukannya jika kita menggunakan ekstensi ORM deklaratif?

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

Saya mau indeks pada kolom "a" dan "b".

yorjo
sumber
1
Pertanyaannya agak tidak jelas tentang apakah Anda menginginkan beberapa indeks atau satu indeks pada beberapa kolom (dan lebih bingung sebelum saya mengeditnya - awalnya dengan senang hati meminta "indeks yang berisi beberapa indeks" ). Tapi tidak masalah, saya rasa, karena jawaban zzzeek membahas kedua kasus tersebut.
Mark Amery

Jawaban:

142

itu hanya Columnobjek, index = True flag bekerja secara 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)

jika Anda ingin indeks komposit, lagi Table- lagi hadir di sini seperti biasa Anda tidak perlu mendeklarasikannya, semuanya bekerja sama (pastikan Anda menggunakan 0.6 atau 0.7 terbaru untuk pembungkus deklaratif Aa untuk ditafsirkan sebagai Columnsetelah deklarasi kelas selesai):

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)

Dalam 0,7 Indexdapat juga di Tableargumen, yang dengan deklaratif adalah melalui __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
sumber
1
Terima kasih, saya diperbarui untuk 0,7 dan menggunakan table_args bekerja dengan baik
yorjo
6
Apa yang terjadi jika Anda memiliki kamus untuk table_args seperti yang saya lakukan saat ini? table_args = {'mysql_engine': 'InnoDB'}
Nick Holden
7
Jadi saya kira saya bisa melakukan table_args = (Indeks ('my_index', "a", "b"), {'mysql_engine': 'InnoDB'})
Nick Holden
1
@RyanChou docs.sqlalchemy.org/en/latest/orm/extensions/declarative/… "Argumen kata kunci dapat ditentukan dengan formulir di atas dengan menentukan argumen terakhir sebagai kamus"
zzzeek
13

Untuk melengkapi jawaban @ zzzeek .

Jika Anda ingin menambahkan indeks komposit dengan DESC dan menggunakan metode deklaratif ORM, Anda dapat melakukan hal berikut.

Selain itu, saya berjuang dengan dokumentasi Indeks Fungsional SQSAlchemy, mencoba mencari cara untuk menggantinya mytable.c.somecol.

from sqlalchemy import Index

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

Kita bisa menggunakan properti model dan memanggilnya .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),
    )

Jika Anda menggunakan Alembic, saya menggunakan Flask-Migrate, itu menghasilkan sesuatu seperti:

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

Terakhir, Anda harus memiliki tabel dan indeks berikut di database PostgreSQL Anda:

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
sumber