Nir*_*Izr 2 postgresql sqlalchemy
作为日常流程的一部分,我插入大量数据,我知道这些数据实际上不会使任何外键约束无效。为了加快速度,一些资源建议暂时删除任何索引或约束,并在插入准备好后重新应用它们。我知道这是有风险的,但仍然想尝试使用 SqlAlchemy。我没有添加任何手动约束,唯一的约束是 SqlAlchemy 由于外键和主键而定义的约束。
我的问题是:如何使用 SqlAlchemy API 暂时删除任何约束/索引,执行一组事务,然后再次应用自动生成的约束?
我希望有比手动操作更方便的方法。
谢谢!
我不了解 SqlAlchemy,但这对于 SQL 来说并不是很难。
对于 table my_table,构建一组DROP CONSTRAINT/ADD CONSTRAINT语句:
SELECT
format('ALTER TABLE %s DROP CONSTRAINT %s', conrelid::regclass, conname),
format('ALTER TABLE %s ADD CONSTRAINT %s %s', conrelid::regclass, conname, pg_get_constraintdef(oid))
FROM pg_constraint
WHERE conrelid = 'my_table'::regclass
Run Code Online (Sandbox Code Playgroud)
...对于索引也类似,跳过与约束相关的任何内容:
SELECT
'DROP INDEX ' || indexrelid::regclass,
pg_get_indexdef(indexrelid)
FROM pg_index
WHERE indrelid = 'my_table'::regclass AND
NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conindid = indexrelid)
Run Code Online (Sandbox Code Playgroud)
然后只需运行删除脚本,加载数据,并在完成后运行添加脚本(当然,所有这些都在事务内)。
有一个缺点:当外键约束被添加回来时,所有数据都将被重新检查,如果您确信它全部有效,那么这将是很多不必要的工作。
有几种方法可以在保留 FK 约束的同时抑制检查(尽管两者都需要超级用户权限):
ALTER TABLE ... DISABLE TRIGGER ALL,其中包括用于 FK 检查的系统触发器。(这是永久性的,完成后您需要重新启用触发器。)SET session_replication_role = 'replica'基本上声明您是一个复制过程(假设已经在源处执行了 FK 检查)。将这些权限之一传递给非超级用户的最简单方法是为其指定默认值session_replication_role:
ALTER ROLE data_loader SET session_replication_role = 'replica'
Run Code Online (Sandbox Code Playgroud)
任何比这更细粒度的东西可能都需要包装在一个SECURITY DEFINER函数中(以其创建者的权限执行,而不是其调用者),加载过程可以随意调用该函数。例如,禁用当前事务其余部分的触发器:
CREATE FUNCTION disable_triggers_for_current_transaction() RETURNS void AS $$
SET LOCAL session_replication_role = 'replica'
$$
LANGUAGE sql
SECURITY DEFINER;
REVOKE ALL ON FUNCTION disable_triggers_for_current_transaction() FROM PUBLIC;
GRANT EXECUTE ON FUNCTION disable_triggers_for_current_transaction() TO data_loader;
Run Code Online (Sandbox Code Playgroud)
或者禁用特定表上的触发器:
CREATE FUNCTION disable_triggers(TableID REGCLASS) RETURNS void AS $$
BEGIN
EXECUTE pg_catalog.format('ALTER TABLE %s DISABLE TRIGGER ALL', TableID);
END
$$
LANGUAGE plpgsql
SECURITY DEFINER;
REVOKE ALL ON FUNCTION disable_triggers(REGCLASS) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION disable_triggers(REGCLASS) TO data_loader;
Run Code Online (Sandbox Code Playgroud)
当然,如果您决定使用这些选项中的任何一个,您将希望在构建这些脚本时保留 FK 约束DROP;只需添加AND contype <> 'f'到第一个WHERE子句即可。