Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python SQLAlchemy是在我试图删除一行时执行额外的选择_Python_Postgresql_Sqlalchemy - Fatal编程技术网

Python SQLAlchemy是在我试图删除一行时执行额外的选择

Python SQLAlchemy是在我试图删除一行时执行额外的选择,python,postgresql,sqlalchemy,Python,Postgresql,Sqlalchemy,TL;博士 我在生产中遇到超时错误: OperationalError: (QueryCanceledError) canceling statement due to statement timeout CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."tableY" x WHERE $1 OPERATOR(pg_catalog.=) "tableX_id" FOR KEY SHARE OF x" 'DELETE FROM tableX

TL;博士

我在生产中遇到超时错误:

OperationalError: (QueryCanceledError) canceling statement due to statement timeout CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."tableY" x WHERE $1 OPERATOR(pg_catalog.=) "tableX_id" FOR KEY SHARE OF x" 'DELETE FROM tableX WHERE tableX.id = %(id)s' {'id': 42}
OperationalError: (QueryCanceledError) canceling statement due to statement timeout CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."tableY" x WHERE $1 OPERATOR(pg_catalog.=) "tableX_id" FOR KEY SHARE OF x" 'DELETE FROM tableX WHERE tableX.id = %(id)s' {'id': 42}
主要原因是仅从public.tableY x中选择1,因为字段tableX_id没有索引。我正在尝试找出此查询的来源,我不需要此检查

充分解释

我有两个表,tableX和tableY,关系在sqlalchemy的tableY中定义为:

class TableY(Base):
    ...
    tableX = relationship(
        'TableX',
        backref=backref(
            'rows_y',
            uselist=True,
            lazy='dynamic',
        ),
        uselist=False,
    )
在SQL中

create table if not exists tableY
(
...
tableX_id integer not null
    constraint fk_tableX_id_tableY
        references state_purchase
            on update cascade on delete restrict,
)
我正试图从表中删除一行

tableX_obj.delete()
SQLAlchemy还试图用外键删除所有相关行,因此在执行删除查询之前,它会执行

SELECT id FROM tableY where tableX_id=42
但是tableY是一个多对多关系表,所以它在tableX_id字段上没有索引,这会导致超时

创建索引不是一个好的解决方案,因为它将是无用的:我确信,当我执行删除操作时,将不会有任何相关记录,因此我将有相当大的索引,其中不包含任何相关信息。它将只包含一个垃圾信息

因此,我希望DB能够处理这种情况,并添加了被动_deletes=True

它似乎解决了一个问题,但现在我在生产中遇到了新的超时错误:

OperationalError: (QueryCanceledError) canceling statement due to statement timeout CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."tableY" x WHERE $1 OPERATOR(pg_catalog.=) "tableX_id" FOR KEY SHARE OF x" 'DELETE FROM tableX WHERE tableX.id = %(id)s' {'id': 42}
OperationalError: (QueryCanceledError) canceling statement due to statement timeout CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."tableY" x WHERE $1 OPERATOR(pg_catalog.=) "tableX_id" FOR KEY SHARE OF x" 'DELETE FROM tableX WHERE tableX.id = %(id)s' {'id': 42}
什么可以执行这个查询?这是来自炼金术吗?如果是,我如何禁用它

PostgreSQL 9.4
SQLAlchemy 0.9.8是的,我知道:

额外的选择是由Postgresql本身完成的,目的是强制执行外键约束及其删除限制。Postgresql正在检查表Y中是否有任何行引用了表X中要删除的行。您可以通过一些测试表轻松地重现这种情况,并设置一个低得离谱的语句超时:

开始 创建表foo id串行主键 ; 创建表格栏 foo_id int在删除限制时引用foo id ; 在foo中插入默认值; 在foo中插入默认值; 从generate_Series11000001中选择2,插入到条中; -超时5毫秒 set语句_timeout=5; -尝试删除未在栏中引用的行,以便扫描 从foo中删除,其中id=1; 回降; 结果是:

BEGIN
CREATE TABLE
CREATE TABLE
INSERT 0 1
INSERT 0 1
INSERT 0 1000001
SET
psql:test.sql:18: ERROR:  canceling statement due to statement timeout
CONTEXT:  SQL statement "SELECT 1 FROM ONLY "public"."bar" x WHERE $1 OPERATOR(pg_catalog.=) "foo_id" FOR KEY SHARE OF x"
ROLLBACK

,但您必须知道自己在做什么,以免破坏引用完整性。另一个选择是考虑是否需要删除限制,或者仅仅创建索引;您提到表Y是一个关联表,因此引用表X id的列可能应该是其主键的一部分。虽然您确定删除时Y中没有引用X的行,但如果不进行检查,数据库将无法知道这一点。

额外的选择是由Postgresql本身完成的,以便强制执行外键约束及其删除时的约束。Postgresql正在检查表Y中是否有任何行引用了表X中要删除的行。您可以通过一些测试表轻松地重现这种情况,并设置一个低得离谱的语句超时:

开始 创建表foo id串行主键 ; 创建表格栏 foo_id int在删除限制时引用foo id ; 在foo中插入默认值; 在foo中插入默认值; 从generate_Series11000001中选择2,插入到条中; -超时5毫秒 set语句_timeout=5; -尝试删除未在栏中引用的行,以便扫描 从foo中删除,其中id=1; 回降; 结果是:

BEGIN
CREATE TABLE
CREATE TABLE
INSERT 0 1
INSERT 0 1
INSERT 0 1000001
SET
psql:test.sql:18: ERROR:  canceling statement due to statement timeout
CONTEXT:  SQL statement "SELECT 1 FROM ONLY "public"."bar" x WHERE $1 OPERATOR(pg_catalog.=) "foo_id" FOR KEY SHARE OF x"
ROLLBACK
,但您必须知道自己在做什么,以免破坏引用完整性。另一个选择是考虑是否需要删除限制,或者仅仅创建索引;您提到表Y是一个关联表,因此引用表X id的列可能应该是其主键的一部分。虽然您确定删除时Y中没有引用X的行,但如果不进行检查,数据库将无法知道这一点