Chỉ mục nhiều cột khi sử dụng phần mở rộng ORM khai báo của sqlalchemy


95

Theo tài liệu và các chú thích trong sqlalchemy.Columnlớp, chúng ta nên sử dụng lớp sqlalchemy.schema.Indexđể chỉ định một chỉ mục chứa nhiều cột.

Tuy nhiên, ví dụ cho thấy cách thực hiện bằng cách sử dụng trực tiếp đối tượng Table như sau:

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)

Chúng ta nên làm như thế nào nếu chúng ta sử dụng phần mở rộng ORM khai báo?

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

Tôi muốn có một chỉ mục trên cột "a" và "b".


1
Câu hỏi hơi không rõ ràng về việc bạn muốn có nhiều chỉ mục hay một chỉ mục duy nhất trên nhiều cột (và đã bối rối hơn trước khi tôi chỉnh sửa nó - ban đầu nó rất thú vị khi yêu cầu "một chỉ mục chứa nhiều chỉ mục" ). Nhưng không có vấn đề gì, tôi đoán, vì câu trả lời của zzzeek giải quyết cả hai trường hợp.
Mark Amery

Câu trả lời:


138

đó chỉ là Columncác đối tượng, cờ index = True hoạt động bình thường:

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

nếu bạn muốn một chỉ mục tổng hợp, một lần nữa Tablexuất hiện ở đây như bình thường, bạn không cần phải khai báo nó, mọi thứ hoạt động giống nhau (đảm bảo rằng bạn đang ở 0,6 hoặc 0,7 gần đây để trình bao bọc Aa khai báo được hiểu là Columnsau khi khai báo lớp hoàn tất):

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)

Trong 0,7, Indexcó thể cũng có trong các Tableđối số, mà với khai báo là thông qua __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"), )

1
Cảm ơn, tôi cập nhật để 0.7 và sử dụng table_args hoạt động tốt
yorjo

6
Điều gì xảy ra nếu bạn có một từ điển cho table_args như tôi hiện đang làm? table_args = {'mysql_engine': 'InnoDB'}
Nick Holden


7
Vì vậy, tôi đoán tôi có thể làm table_args = (Index ( 'my_index', "a", "b"), { 'mysql_engine': 'InnoDB'})
Nick Holden

1
@RyanChou docs.sqlalchemy.org/en/latest/orm/extensions/declarative/... "đối số từ khóa có thể được xác định với các hình thức trên bằng cách xác định đối số cuối cùng như một cuốn từ điển"
zzzeek

13

Để hoàn thành câu trả lời của @ zzzeek .

Nếu bạn muốn thêm chỉ mục tổng hợp với DESC và sử dụng phương pháp khai báo ORM, bạn có thể làm như sau.

Hơn nữa, tôi đang vật lộn với tài liệu Chỉ mục chức năng của SQSAlchemy, cố gắng tìm ra cách thay thế mytable.c.somecol.

from sqlalchemy import Index

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

Chúng ta chỉ có thể sử dụng thuộc tính model và gọi .desc()nó:

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),
    )

Nếu bạn sử dụng Alembic, tôi đang sử dụng Flask-Migrate, nó tạo ra một cái gì đó như:

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

Cuối cùng, bạn sẽ có bảng và chỉ mục sau trong cơ sở dữ liệu PostgreSQL của mình:

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.