最快检查PostgreSQL中是否存在行

时间:2011-09-19 13:22:15

标签: sql postgresql

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

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

但是因为我对PostgreSQL很新,所以我宁愿问那些知道的人。

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

userid | rightid | remaining_count

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

9 个答案:

答案 0 :(得分:247)

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

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

答案 1 :(得分:30)

简单地说:

select 1 from tbl where userid = 123 limit 1;

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

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

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

  

如果表中存在批处理中的单行,那么我就是这样   不必插入我的行,因为我知道他们都是   插入

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

答案 2 :(得分: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 ...
    )       
    ;

BTW:如果你希望整批失败,如果有重复,那么(给定主键约束)

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

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

答案 3 :(得分:1)

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);

答案 4 :(得分:1)

@MikeM指出。

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

索引保持联系,通常可以将时间成本降低到1毫秒。

CREATE INDEX index_contact on contact(id);

答案 5 :(得分:0)

SELECT 1 FROM user_right where userid = ? LIMIT 1

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

答案 6 :(得分:0)

如果您考虑性能,也许您可​​以在这样的函数中使用“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;

答案 7 :(得分:0)

经验法则

  

选择存在(       从xx中选择true,其中xx     )" 1 + 1加起来是2&#34 ;;

答案 8 :(得分:0)

我想提出另一种想法来专门解决您的句子:“因此,我想检查表中是否存在该批次中的一行,因为那么我知道它们都是 插入。”

您通过插入“批”来提高效率,但是然后一次进行一次存在性检查?这对我来说似乎很直觉。因此,当您说“ 插入总是成批完成”时,我想您是说您要使用一个插入语句插入多个记录。您需要认识到Postgres符合ACID。如果您要通过一条插入语句插入多条记录(一批数据),则无需检查是否已插入某些记录。该语句要么通过,要么失败。将插入所有记录或不插入所有记录。

另一方面,如果您的C#代码只是在循环中简单地“设置”单独的插入语句,并且在您的脑海中,这是一个“批处理” ..那么您实际上不应描述因为“插入总是分批完成”。您期望实际上可能未插入“批处理”部分的事实,因此感到需要检查,这一事实强烈表明了这种情况,在这种情况下,您有一个更根本的问题。您需要更改范例,以便实际上一次插入多个记录,并放弃检查是否有单个记录。

考虑以下示例:

CREATE TABLE temp_test (
    id SERIAL PRIMARY KEY,
    sometext TEXT,
    userid INT,
    somethingtomakeitfail INT unique
)
-- insert a batch of 3 rows
;;
INSERT INTO temp_test (sometext, userid, somethingtomakeitfail) VALUES
('foo', 1, 1),
('bar', 2, 2),
('baz', 3, 3)
;;
-- inspect the data of what we inserted
SELECT * FROM temp_test
;;
-- this entire statement will fail .. no need to check which one made it
INSERT INTO temp_test (sometext, userid, somethingtomakeitfail) VALUES
('foo', 2, 4),
('bar', 2, 5),
('baz', 3, 3)  -- <<--(deliberately simulate a failure)
;;
-- check it ... everything is the same from the last successful insert ..
-- no need to check which records from the 2nd insert may have made it in
SELECT * FROM temp_test

这实际上是任何符合ACID的数据库的范式..不仅仅是Postgresql。换句话说,如果您解决了“批处理”的概念,而不必首先进行逐行检查,那么情况会更好。