如何在PostgreSQL中通过排序删除固定数量的行?

Wha*_*sit 94 sql postgresql

我正在尝试将一些旧的MySQL查询移植到PostgreSQL,但我遇到了这个问题:

DELETE FROM logtable ORDER BY timestamp LIMIT 10;
Run Code Online (Sandbox Code Playgroud)

PostgreSQL不允许对其删除语法进行排序或限制,并且该表没有主键,因此我无法使用子查询.此外,我想保留在查询删除的行为究竟该规定数量的记录-例如,如果表中包含30行,但它们都具有相同的时间戳,我还是想删除10,虽然它并不重要哪10.

所以; 如何在PostgreSQL中通过排序删除固定数量的行?

编辑:没有主键意味着没有log_id列或类似.啊,遗留系统的乐趣!

mu *_*ort 144

您可以尝试使用ctid:

DELETE FROM logtable
WHERE ctid IN (
    SELECT ctid
    FROM logtable
    ORDER BY timestamp
    LIMIT 10
)
Run Code Online (Sandbox Code Playgroud)

ctid方法是:

行版本在其表中的物理位置.请注意,虽然ctid可以非常快速地定位行版本,但ctid如果更新或移动行,则行将更改VACUUM FULL.因此ctid作为长期行标识符是无用的.

还有,oid但只有在创建表时特别要求它才存在.

  • 这有效,但它有多可靠?有什么我需要注意的“陷阱”吗?如果 `VACUUM FULL` 或 autovacuum 在查询运行时更改表中的 `ctid` 值,它们是否可能导致问题? (2认同)
  • 增量VACUUM不会改变ct​​ids,我不这么认为.因为它只是在每个页面内压缩,而ctid只是行号而不是页面偏移量.VACUUM FULL或CLUSTER操作*将*更改ctid,但这些操作首先对表进行访问独占锁定. (2认同)

小智 43

Postgres文档建议使用数组而不是IN和子查询.这应该更快

DELETE FROM logtable 
WHERE id = any (array(SELECT id FROM logtable ORDER BY timestamp LIMIT 10));
Run Code Online (Sandbox Code Playgroud)

这里和其他一些技巧可以在这里找到

  • 如果`any(array(...));`比`in(...)`更快,听起来像查询优化器中的错误 - 它应该能够发现转换并对数据执行相同的操作本身. (6认同)
  • 对 12 GB 表的测量:第一个查询 450..1000 毫秒,第二个查询 5..7 秒:快速查询:从 cs_logging 中删除,其中 id = any (array( select id from cs_logging where date_created < now() - 间隔 '1 天' * 30 和partition_key like '%I' order by id limit 500 )) 慢一个:从cs_logging中删除,其中id in ( select id from cs_logging where date_created < now() - 间隔'1天' * 30和partition_key like '%我按 id 限制 500 订购)。使用 ctid 慢很多(几分钟)。 (4认同)
  • @BlakeRegalia 否,因为指定的表中没有主键。这将删除前 10 行中找到的具有“ID”的所有行。如果所有行都具有相同的 ID,则所有行都将被删除。 (2认同)

Kon*_*rus 12

delete from logtable where log_id in (
    select log_id from logtable order by timestamp limit 10);
Run Code Online (Sandbox Code Playgroud)


小智 5

如果没有主键,可以将数组Where IN 语法与组合键一起使用。

delete from table1 where (schema,id,lac,cid) in (select schema,id,lac,cid from table1 where lac = 0 limit 1000);
Run Code Online (Sandbox Code Playgroud)

这对我有用。