sqlalchemyの宣言的ORM拡張を使用する場合の複数列のインデックス


94

ドキュメント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の回答は両方のケースに対応しているので、私は推測します。
マークアメリー2018年

回答:


137

これらは単なる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

5
私のようにtable_argsの辞書があるとどうなりますか?table_args = {'mysql_engine': 'InnoDB'}
Nick Holden


6
したがって、私はtable_args =(Index( 'my_index'、 "a"、 "b")、{'mysql_engine': 'InnoDB'})を実行できると思います
Nick Holden

1
@ RyanChoudocs.sqlalchemy.org / en / latest / orm / extensions / declarative / 「キーワード引数は、最後の引数を辞書として指定することにより、上記の形式で指定できます」
zzzeek

12

@zzzeekの回答を完了するには

DESCを使用して複合インデックスを追加し、ORM宣言メソッドを使用する場合は、次のように実行できます。

さらに、私はSQSAlchemyの関数型インデックスのドキュメントに苦労して、置換する方法を見つけようとしました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.