Fastest check if row exists in PostgreSQL
我有一堆行需要插入到表中,但这些插入总是分批完成。 所以我想检查表中是否存在批处理中的单行,因为我知道它们都已插入。
所以它不是主键检查,但不应该太重要。 我想只检查单行,所以count(*)可能不好,所以它的类似exists我猜。
但是因为我对PostgreSQL相当新,所以我宁愿问那些知道的人。
我的批处理包含具有以下结构的行:
| 1
 | userid | rightid | remaining_count | 
因此,如果表包含提供userid的任何行,则表示它们都存在于那里。
		
		
- 
您想查看表中是否有任何行或批处理中的任何行?
- 
来自我的批次的任何行是。他们都共享相同的领域病态编辑一点。
- 
请澄清你的问题。您想要添加一批记录,全部或全部?伯爵有什么特别之处吗? (BTW保留字,作为列名不切实际)
- 
好吧,我试图简化实际情况,但我们越来越接近真正的实施。插入这些行后(另一个字段为for_date)我开始递减指定用户的权限,因为他们使用特定权限,一旦权限变为0,他们就不能再执行那些日期的操作。这就是真实的故事
- 
只需显示表定义(相关部分),并告诉您打算做什么。
- 
[userid,rightid,for_date,remainingCount]就是真正的表格。当用户尝试使用任何权限时,我打算插入此表。我本可以创建一个特殊的进程,负责每天插入行,但目前我正在检查另一种方法是否适合我的性能。
- 
remainingCount的大写字母为"C"?我建议坚持小写(remaining_count),否则你总是要引用这个标识符:"remainingCount"。也没有"postgre"之类的东西。这是"PostgreSQL"或"postgres"。最后,仍然不清楚一次插入的所有行是否共享相同的用户ID。
- 
那好吧。我从C#代码的参数列表中复制粘贴,不要担心Erwin。我认为应该很清楚,但要指定更多,批处理包含共享userid的行,这就是为什么,检查具有指定userid的单行首先是有意义的..
 
	 
使用EXISTS关键字返回TRUE / FALSE:
| 1
 | 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。我做错了什么?
- 
@FiftiN ::这可能会回答你的问题:stackoverflow.com/questions/5203755/…
- 
@ Michael.M我有30万行的DB表,当我使用exists或limit 1时,我的性能下降很强,因为Postgres使用Seq Scan而不是Index Scan。并且analyze没有帮助。
- 
子查询中的limit 1会帮助或减慢查询吗?
- 
@maciek请理解'id'是主键,因此"LIMIT 1"将毫无意义,因为只有一个记录带有该id
 
	 
怎么样简单:
| 1
 | SELECT 1 FROM tbl WHERE userid = 123 LIMIT 1; | 
其中123是您要插入的批次的用户ID。
上述查询将返回空集或单行,具体取决于是否存在具有给定用户标识的记录。
如果结果太慢,您可以考虑在tbl.userid上创建索引。
if even a single row from batch exists in table, in that case I
  don't have to insert my rows because I know for sure they all were
  inserted.
为了使这一点保持正确,即使您的程序在批处理中被中断,我建议您确保正确管理数据库事务(即整个批处理插入单个事务中)。
		
		
- 
当然,即时通讯使用交易
- 
有时可能在编程上更容易"从(选择1 ...限制1)中选择计数(*),因为它保证始终返回值为count(*)为0或1的行。
- 
@DavidAldridge计数(*)仍然表示必须读取所有行,而限制1在第一个记录处停止并返回
- 
@Imraan我认为你误解了这个问题。 COUNT作用于最多有1行的嵌套SELECT(因为LIMIT在子查询中)。
 
	 
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | 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 ...
 )
 ;
 | 
顺便说一句:如果你希望整个批次在重复的情况下失败,那么(给定主键约束)
| 12
 3
 4
 
 | INSERT INTO target( userid, rightid, COUNT )SELECT userid, rightid, COUNT
 FROM batch
 ;
 | 
会做你想做的事:要么成功,要么失败。
		
		
- 
这将检查每一行。他想做一次检查。
- 
不,它只进行一次检查。子查询是不相关的。一旦发现一对配对,它将纾困。
- 
你是对的,我以为它引用了外部查询。 +1给你
- 
BTW:由于查询在事务内部,如果要插入重复的id,则不会发生任何事情,因此可以省略子查询。
- 
嗯我不确定我理解。插入权限后,我开始递减计数列。 (只是图片的一些细节)如果行已经存在并且子查询被省略,我认为生成错误时会抛出重复的唯一键或者? (userid& right表示唯一键)
 
	 
| 1
 | SELECT TRUE FROM tablename WHERE condition LIMIT 1; | 
我相信这是postgres用于检查外键的查询。
在你的情况下,你也可以一气呵成:
| 1
 | INSERT INTO yourtable SELECT $userid, $rightid, $count WHERE NOT (SELECT TRUE FROM yourtable WHERE userid = $userid LIMIT 1); | 
经验法则
select exists (
      select true from xx where xx
    ) as"Does 1+1 adds up to 2";
如果你考虑性能,可能是你可以在函数中使用"PERFORM",如下所示:
| 12
 3
 4
 5
 6
 
 |  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"的语法错误
 
	 
| 1
 | SELECT 1 FROM user_right WHERE userid = ? LIMIT 1 | 
如果结果集包含一行,则不必插入。否则插入您的记录。
		
		
- 
如果束包含100行,它将返回100行,你认为那好吗?
- 
您可以将其限制为1行。应该表现更好。看看来自@aix的编辑回答。