在 PostgreSQL 中查找所有列重复且没有唯一字段的行

Find rows with all columns duplicated and no unique field in PostgreSQL

假设我有一个这样的 table,其中没有任何列或列组合保证是唯一的:

GAME_EVENT USERNAME ITEM QUANTITY
sell poringLUVR sword 1
sell poringLUVR sword 1
kill daenerys civilians 200000
kill daenerys civilians 200000
invoke sylvanas undead 1000000

我想检索存在不止一次的所有行的列表(其中所有列的组合出现不止一次)。

(在这种情况下,我希望得到一个包含“sell/poringLUVR”和“kill/daenerys”行的列表)

解决这个问题的好方法是什么?合并索引会有帮助吗?也欢迎对非 Postgres 方法提出建议。

假设所有列 NOT NULL,这将执行:

SELECT *
FROM   tbl t1
WHERE  EXISTS (
   SELECT FROM tbl t2
   WHERE  (t1.*) = (t2.*)
   AND    t1.ctid <> t2.ctid
   );

ctid is a system column,在没有实际PK(你显然没有)的情况下,可以作为穷人PK的“元组标识符”/“项目指针”,并且只能在单个查询的范围。相关:

如果列可以是 NULL,(成本更高)使用 IS NOT DISTINCT FROM 而不是 = 进行操作。参见:

  • How do I (or can I) SELECT DISTINCT on multiple columns?

(t1.*) = (t2.*) 正在比较 ROW 值。这个较短的语法是等效的:t1 = t2 除非底层 table 中存在同名的列,在这种情况下,第二种形式失败而第一种形式不会。参见:

索引?

如果任何列具有特别高的基数(许多不同的值,很少重复),为了这个答案的目的,我们称之为 hi_cardi_column,仅在该列上的普通 btree 索引可能是有效的为你的任务。一些小列与多列索引的组合也可以工作。关键是要有一个小而快的索引,否则开销不会支付。

SELECT *
FROM   tbl t1
WHERE  EXISTS (
   SELECT FROM tbl t2
   WHERE  t1.hi_cardi_column = t2.hi_cardi_column -- logically redundant
   AND    (t1.*) = (t2.*)
   AND    t1.ctid <> t2.ctid
   );

添加的条件t1.hi_cardi_column = t2.hi_cardi_column在逻辑上是多余的,但有助于利用所述索引。

除此之外,我认为索引支持的潜力不大,因为无论如何都必须访问 table 的所有行,并且必须检查所有列。