具有多个数据库的 SQLAlchemy 因重复创建索引而出错

Bhu*_*han 5 python sqlite postgresql sqlalchemy

我们有一个包含两个表的 postgres 数据库Models,并且Drives我们使用 sqlalchemy 创建查询来分析这些表中的数据。

Models表具有以下架构:

CREATE TABLE models (
    id SERIAL PRIMARY KEY,
    vendor_name character varying(32) NOT NULL,
    model character varying(32) NOT NULL,
    drive_capacity bigint NOT NULL
);

-- Indices -------------------------------------------------------

CREATE UNIQUE INDEX models_pkey ON models(id int4_ops);
CREATE INDEX idx_models_vendor_name ON models(vendor_name text_ops);
CREATE INDEX idx_models_model ON models(model text_ops); 
Run Code Online (Sandbox Code Playgroud)

Models并由以下类表示tables.py

class Models(Base, DeferredReflection):
    __tablename__ = "models"
    id = Column("id", Integer, primary_key=True)
Run Code Online (Sandbox Code Playgroud)

Drives表具有以下架构:

CREATE TABLE drives (
    id SERIAL PRIMARY KEY,
    serial_number character varying(32) NOT NULL UNIQUE,
    model integer NOT NULL REFERENCES models(id),
    role character varying(16) NOT NULL
);

-- Indices -------------------------------------------------------

CREATE UNIQUE INDEX drives_pkey ON drives(id int4_ops);
CREATE UNIQUE INDEX drives_serial_number_key ON drives(serial_number text_ops);
CREATE INDEX drives_role_idx ON drives(role text_ops);
CREATE INDEX index_drives_model_fk ON drives(model int4_ops);
Run Code Online (Sandbox Code Playgroud)

Drives并用以下类表示tables.py

class Drives(Base, DeferredReflection):
    __tablename__ = "drives"
    id = Column("id", Integer, primary_key=True)
    model = Column("model", Integer, ForeignKey(Models.id), nullable=False)
Run Code Online (Sandbox Code Playgroud)

您可以注意到,这两个表都在特定列上创建了附加索引。在我们的单元测试基础设施中,我们创建一个内存中的 sqlite 数据库,并创建与 postgresql 数据库具有相同架构的表和索引。然后,我们将假行插入到 sqlite 实例中,在 sqlite 数据库上运行真实查询并检查真实查询的正确性。代码如下所示:

sqlite_engine = create_engine('sqlite:///', echo=True)
from tables import Base
Base.metadata.create_all(bind=sqlite_engine)
# add fake rows to sqlite
# run real query on sqlite engine
# compare against expected output to confirm correctness of real queries.
Run Code Online (Sandbox Code Playgroud)

但是,我在上面的步骤中遇到错误create_all。虽然我能够创建模型表及其索引,但我收到该drives表的索引已存在错误:

cursor = <sqlite3.Cursor object at 0x7f466b877570>
statement = 'CREATE INDEX index_drives_model_fk ON drives (model)'
parameters = ()
context = <sqlalchemy.dialects.sqlite.base.SQLiteExecutionContext object at 0x7f466b2f4160>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) index index_drives_model_fk already exists [SQL: 'CREATE INDEX index_drives_model_fk ON drives (model)'] (Background on this error at: http://sqlalche.me/e/e3q8)
Run Code Online (Sandbox Code Playgroud)

使用echo=True,我注意到 SQLAlchemy 发出以下语句:

CREATE TABLE models (
    id INTEGER NOT NULL,
    vendor_name VARCHAR(32) NOT NULL,
    model VARCHAR(32) NOT NULL,
    drive_capacity BIGINT NOT NULL,
    CONSTRAINT models_pkey PRIMARY KEY (id)
)
log.py                     110 INFO     COMMIT
log.py                     110 INFO     CREATE INDEX idx_models_model ON models (model)
log.py                     110 INFO     COMMIT
log.py                     110 INFO     CREATE INDEX idx_models_vendor_name ON models (vendor_name)
log.py                     110 INFO     COMMIT
log.py                     110 INFO
CREATE TABLE drives (
    id INTEGER NOT NULL,
    model INTEGER NOT NULL,
    serial_number VARCHAR(32) NOT NULL,
    role VARCHAR(16) NOT NULL,
    CONSTRAINT drives_pkey PRIMARY KEY (id),
    FOREIGN KEY(model) REFERENCES models (id),
    CONSTRAINT drives_serial_number_key UNIQUE (serial_number),
    CONSTRAINT drives_serial_number_key UNIQUE (serial_number)
)
log.py                     110 INFO     COMMIT
log.py                     110 INFO     CREATE INDEX index_drives_model_fk ON drives (model)
log.py                     110 INFO     COMMIT
log.py                     110 INFO     CREATE INDEX drives_role_idx ON drives (role)
log.py                     110 INFO     COMMIT
log.py                     110 INFO     CREATE INDEX index_drives_model_fk ON drives (model) <<<<<<---- Why create index_drives_model_fk twice?
log.py                     110 INFO     ROLLBACK
Run Code Online (Sandbox Code Playgroud)

如果您注意到上面代码片段的最后 6 行,您会发现它index_drives_model_fk被创建了两次,因此出现了错误。我的问题:是什么使 sqlalchemy 向drives表发出两个索引创建,但models表(以及关联的索引)似乎已正确创建?我还可以确认如果我从 postgres表中删除drives_role_idx和,那么事情就会按预期正常工作。index_drives_model_fkdrive