#python #postgresql #sqlite #sqlalchemy
#python #postgresql #sqlite #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);
и представлен Models
классом в tables.py
:
class Models(Base, DeferredReflection):
__tablename__ = "models"
id = Column("id", Integer, primary_key=True)
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);
и представлен 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)
Как вы можете заметить, обе таблицы имеют дополнительные индексы, созданные для определенных столбцов. В нашей инфраструктуре модульного тестирования мы создаем базу данных 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.
Однако я получаю ошибку на create_all
шаге выше. Хотя я могу создать таблицу models и ее индексы, я получаю ошибку index already exists для 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)
С 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
Если вы обратите внимание на последние 6 строк приведенного выше фрагмента, вы увидите, что index_drives_model_fk
создается дважды и, следовательно, ошибка. Мой вопрос: что заставляет sqlalchemy создавать два индекса для drives
таблицы, но models
таблица (и связанные с ней индексы), похоже, созданы правильно? Я также могу подтвердить, что если я удалю drives_role_idx
и index_drives_model_fk
из drive
таблицы postgres, тогда все будет работать правильно, как ожидалось.
Комментарии:
1. вы смогли с этим разобраться?
2. @pkaleta Извините, я не сделал.
3. Смотрите github.com/sqlalchemy/sqlalchemy/issues/7366