sqlalchemy의 선언적 ORM 확장을 사용하는 경우 다중 열 인덱스


95

문서sqlalchemy.Column클래스 의 주석에 따르면 클래스 sqlalchemy.schema.Index를 사용하여 여러 열을 포함하는 인덱스를 지정해야합니다.

그러나 예제에서는 다음과 같이 Table 개체를 직접 사용하여 수행하는 방법을 보여줍니다.

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)

선언적 ORM 확장을 사용하는 경우 어떻게해야합니까?

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

"a"및 "b"열에 대한 색인을 원합니다.


1
질문은 다중 인덱스를 원하는지 아니면 여러 열에 대한 단일 인덱스를 원하는지에 대해 약간 불분명합니다 (그리고 편집하기 전에 더 혼란 스러웠습니다. 원래 "여러 인덱스를 포함하는 인덱스"를 요청했습니다 ). 그러나 상관없이 zzzeek의 답변이 두 경우를 모두 다루기 때문에 추측합니다.
Mark Amery

답변:


138

그것들은 단지 Column객체입니다. index = True 플래그는 정상적으로 작동합니다.

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

복합 색인을 원하면 Table평소처럼 여기에 다시 존재합니다. 선언 할 필요가 없습니다. 모든 것이 동일하게 작동합니다 (선언적 Aa 래퍼가 다음과 같이 해석되도록 최근 0.6 또는 0.7에 있는지 확인하십시오. Column클래스 선언이 완료된 후) :

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)

0.7에서는 인수에도 Index포함될 수 있으며 Table선언적으로 다음을 통해 수행됩니다 __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
덕분에, 나는 0.7로 업데이트하고 사용 table_args 것은 잘 작동
yorjo

6
내가 현재하는 것처럼 table_args에 대한 사전이 있으면 어떻게됩니까? table_args = { 'mysql_engine': 'InnoDB'}
Nick Holden


7
내가 할 수있는 것 같아요 그래서 table_args = (지수 ( 'my_index를', "A", "B") { 'mysql_engine': '이노'})
닉 홀든

1
@RyanChou docs.sqlalchemy.org/en/latest/orm/extensions/declarative/... "키워드 인수는 사전으로 마지막 인수를 지정하여 위의 양식을 지정할 수 있습니다"
zzzeek

13

@zzzeek의 답변 을 완료하려면 .

DESC로 복합 색인을 추가하고 ORM 선언적 방법을 사용하려면 다음과 같이 할 수 있습니다.

또한 SQSAlchemy 의 Functional Indexes 문서를 사용하여를 대체하는 방법을 알아 내려고 애 썼습니다 mytable.c.somecol.

from sqlalchemy import Index

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

모델 속성을 사용하고 호출 .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),
    )

Alembic을 사용하는 경우 Flask-Migrate를 사용하고 있으며 다음과 같은 결과가 생성됩니다.

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

마지막으로 PostgreSQL 데이터베이스에 다음 테이블과 인덱스가 있어야합니다.

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.