ChatGPT解决这个技术问题 Extra ChatGPT

最快检查 PostgreSQL 中是否存在行

我有一堆需要插入到表中的行,但这些插入总是分批完成的。所以我想检查表中是否存在批处理中的一行,因为那时我知道它们都被插入了。

所以它不是一个主键检查,但不应该太重要。我只想检查单行,所以 count(*) 可能不好,所以我猜它类似于 exists

但是由于我对 PostgreSQL 还很陌生,所以我宁愿问知道的人。

我的批次包含具有以下结构的行:

userid | rightid | remaining_count

因此,如果表包含任何带有提供的 userid 的行,则意味着它们都存在于那里。

您想查看该表是否有任何行,或者您的批次中是否有任何行?
我的批次中的任何行是的。他们都共享相同的字段,请稍作编辑。
请澄清你的问题。您要添加一批记录,全部还是全部? count 有什么特别之处吗? (顺便说一句,保留字,作为列名不切实际)
好的,我试图简化实际情况,但我们越来越接近实际实施。插入这些行后(还有另一个字段 for_date),我开始减少指定用户的权限,因为他们使用特定权限,一旦权限变为 0,他们就不能再在该日期执行这些操作。那是真实的故事
只需显示(相关部分)表定义,并告诉您打算做什么。

j
jdhao

使用 EXISTS 关键字返回 TRUE / FALSE:

select exists(select 1 from contact where id=12)

在此扩展,您可以命名返回的列以方便参考。例如select exists(select 1 from contact where id=12) AS "exists"
这更好,因为它总是会返回一个值(true 或 false),而不是有时 None (取决于您的编程语言),这可能不会扩展您期望的方式。
我使用这种方法进行了 Seq Scan。我做错了什么?
@Michael.MI 有 3000 万行的数据库表,当我使用 existslimit 1 时,我的性能下降很大,因为 Postgres 使用 Seq Scan 而不是 Index Scan。 analyze 也无济于事。
子查询中的 limit 1 会帮助还是减慢查询?
N
NPE

简单地说:

select 1 from tbl where userid = 123 limit 1;

其中 123 是您要插入的批次的用户 ID。

上述查询将返回空集或单行,具体取决于是否存在具有给定用户 ID 的记录。

如果结果太慢,您可以考虑在 tbl.userid 上创建索引。

如果表中甚至存在批处理中的单行,在这种情况下,我不必插入我的行,因为我确定它们都已插入。

即使您的程序在批处理中被中断,为了保持这一点,我建议您确保适当地管理数据库事务(即整个批处理插入到单个事务中)。


有时,“从 (select 1 ... limit 1) 中选择 count(*)”可能在编程上更容易,因为它保证总是返回 count(*) 值为 0 或 1 的行。
@DavidAldridge count(*) 仍然意味着必须读取所有行,而 limit 1 在第一条记录处停止并返回
@Imraan 我认为您误解了查询。 COUNT 作用于最多有 1 行的嵌套 SELECT(因为 LIMIT 在子查询中)。
w
wildplasser
INSERT INTO target( userid, rightid, count )
  SELECT userid, rightid, count 
  FROM batch
  WHERE NOT EXISTS (
    SELECT * FROM target t2, batch b2
    WHERE t2.userid = b2.userid
    -- ... other keyfields ...
    )       
    ;

顺便说一句:如果您希望整个批次在重复的情况下失败,那么(给定主键约束)

INSERT INTO target( userid, rightid, count )
SELECT userid, rightid, count 
FROM batch
    ;

将完全按照您的意愿行事:要么成功,要么失败。


这将检查每一行。他想做一次检查。
不,它只进行一次检查。子查询不相关。一旦找到一对匹配的配对,它将退出。
是的,我认为它指的是外部查询。 +1 给你
顺便说一句:由于查询在事务中,如果要插入重复的 id,则不会发生任何事情,因此可以省略子查询。
嗯,我不确定我是否理解。插入权限后,我开始减少计数列。 (只是图片的一些细节)如果行已经存在并且子查询被省略,我认为会抛出重复的唯一键或错误? (userid&right 形成唯一键)
h
hcnak

正如@MikeM 指出的那样。

select exists(select 1 from contact where id=12)

使用 index on contact,通常可以将时间成本降低到 1 ms。

CREATE INDEX index_contact on contact(id);

1ms 的成本是巨大的——每秒只能进行 1000 次这样的检查。应该瞄准每秒大约 10M 的检查。
a
aleroot

如果你考虑一下性能,也许你可以在一个函数中使用“PERFORM”,就像这样:

 PERFORM 1 FROM skytf.test_2 WHERE id=i LIMIT 1;
  IF FOUND THEN
      RAISE NOTICE ' found record id=%', i;  
  ELSE
      RAISE NOTICE ' not found record id=%', i;  
 END IF;

对我不起作用:我在执行附近遇到语法错误
那是 pl/pgsql,而不是 SQL,因此如果尝试将其作为 SQL 运行,则会出现“PERFORM”的语法错误
F
Fabian Barney
SELECT 1 FROM user_right where userid = ? LIMIT 1

如果您的结果集包含一行,那么您不必插入。否则插入您的记录。


如果一堆包含 100 行,它将返回 100 行,你认为这很好吗?
您可以将其限制为 1 行。应该表现更好。请查看@aix 的已编辑答案。
R
Royce
select true from tablename where condition limit 1;

我相信这是 postgres 用于检查外键的查询。

在您的情况下,您也可以一次性完成:

insert into yourtable select $userid, $rightid, $count where not (select true from yourtable where userid = $userid limit 1);