如果大部分行都被删除(大部分是重复的)并且表适合 RAM,请考虑以下路线:
SELECT
将幸存的行放入临时表中。
- 将 FK 引用重新路由到幸存者
DELETE
基表中的所有行。
- 幸存者
INSERT
。
1a。蒸馏幸存的行
CREATE TEMP TABLE tmp AS
SELECT DISTINCT ON (login_name, password) *
FROM (
SELECT DISTINCT ON (email) *
FROM taccounts
ORDER BY email, last_login DESC
) sub
ORDER BY login_name, password, last_login DESC;
关于DISTINCT ON
:
要识别两个不同条件的重复项,请使用子查询一个接一个地应用这两个规则。第一步保留最新的帐户last_login
,因此这是“可序列化的”。
检查结果并测试其合理性。
SELECT * FROM tmp;
临时表会在会话结束时自动删除。在 pgAdmin(您似乎正在使用)中,只要编辑器窗口打开,会话就会存在。
1b。“重复”的更新定义的替代查询
SELECT *
FROM taccounts t
WHERE NOT EXISTS (
SELECT FROM taccounts t1
WHERE ( NULLIF(t1.email, '') = t.email
OR (NULLIF(t1.login_name, ''), NULLIF(t1.password, '')) = (t.login_name, t.password))
AND (t1.last_login, t1.account_id) > (t.last_login, t.account_id)
);
这不会将任何“重复”列中的字符串 ( ) 视为相同NULL
或将空字符串 ( ''
) 视为相同。
行表达式(t1.last_login, t1.account_id)
处理了两个受骗者可能共享相同的可能性last_login
。在这种情况下选择较大的那个account_id
- 这是独一无二的,因为它是 PK。
2a。如何识别所有传入的 FK
SELECT c.confrelid::regclass::text AS referenced_table
, c.conname AS fk_name
, pg_get_constraintdef(c.oid) AS fk_definition
FROM pg_attribute a
JOIN pg_constraint c ON (c.conrelid, c.conkey[1]) = (a.attrelid, a.attnum)
WHERE c.confrelid = 'taccounts'::regclass -- (schema-qualified) table name
AND c.contype = 'f'
ORDER BY 1, contype DESC;
仅在外键的第一列上构建。更多关于:
或者Dependents
在选择表格后在 pgAdmin 的对象浏览器的右侧窗口中检查骑手taccounts
。
2b。重新路由到新的主节点
如果您有表引用taccounts
(传入的外键) taccounts
,您将需要在删除欺骗之前更新所有这些字段。
将它们全部重新路由到新的主行:
UPDATE referencing_tbl r
SET referencing_column = tmp.reference_column
FROM tmp
JOIN taccounts t1 USING (email)
WHERE r.referencing_column = t1.referencing_column
AND referencing_column IS DISTINCT FROM tmp.reference_column;
UPDATE referencing_tbl r
SET referencing_column = tmp.reference_column
FROM tmp
JOIN taccounts t2 USING (login_name, password)
WHERE r.referencing_column = t1.referencing_column
AND referencing_column IS DISTINCT FROM tmp.reference_column;
3. & 4. 杀戮
现在,不再引用骗子了。进入杀戮。
ALTER TABLE taccounts DISABLE TRIGGER ALL;
DELETE FROM taccounts;
VACUUM taccounts;
INSERT INTO taccounts
SELECT * FROM tmp;
ALTER TABLE taccounts ENABLE TRIGGER ALL;
在操作期间禁用所有触发器。这避免了在操作期间检查引用完整性。重新激活触发器后,一切都会好起来的。我们处理了上面所有传入的FK。传出的 FK 保证是健全的,因为您没有并发写入访问权限,并且所有值之前都存在。