哪种 SQL 模式可以更快地避免插入重复行?

Posted

技术标签:

【中文标题】哪种 SQL 模式可以更快地避免插入重复行?【英文标题】:Which SQL pattern is faster to avoid inserting duplicate rows? 【发布时间】:2010-06-25 18:00:30 【问题描述】:

我知道两种不重复插入的方法。第一个是使用WHERE NOT EXISTS 子句:

INSERT INTO table_name (col1, col2, col3)
SELECT %s, %s, %s
WHERE NOT EXISTS (
    SELECT * FROM table_name AS T
    WHERE T.col1 = %s
      AND T.col2 = %s)

另一个在做LEFT JOIN:

INSERT INTO table_name (col1, col2, col3)
SELECT %s, %s, %s
FROM ( SELECT %s, %s, %s ) A
LEFT JOIN table_name B
ON  B.COL1 = %s
AND B.COL2 = %s
WHERE B.id IS NULL
LIMIT 1

对于一个比另一个快,是否有一个一般规则,或者它取决于表?有没有比两者都更好的不同方法?

【问题讨论】:

您确定要在第一个示例中使用 SELECT * 吗?选择所有列?一般来说,不会这样做,但我不是 Postgres 专家。 你能用 EXPLAIN 运行这两个查询并发布吗?分析工具可帮助您逐案回答这些问题。 【参考方案1】:

我建议在您需要唯一的列上定义一个 UNIQUE 约束(在本例中为 col1 和 col2),然后执行 INSERT。根据需要处理异常。


关于您对要求回滚的异常的评论,PostgreSQL 的解决方案是在您尝试可能导致异常的插入之前设置事务保存点。如果遇到异常,回滚到保存点。

见:

http://www.postgresql.org/docs/current/static/sql-savepoint.html http://www.postgresql.org/docs/current/static/sql-rollback-to.html

【讨论】:

我已经有了独特的约束。但是,当它们被违反时,到目前为止,我必须提交或回滚整个事务。不过,我的每笔交易都需要多次插入,我不想部分提交其中的一些。有没有办法以更好的方式处理异常,不会弄乱游标/事务? (从 Python 执行此操作,使用 sqlobject 或 psycopg2) 是:捕获异常。如果它是重复键违规,那么您可以忽略它,因为这意味着您的行已经存在。如果它是另一种类型的异常,无论如何你都会遇到这个问题(例如 SQL 语法错误、磁盘已满、网络连接中断)。 如果我捕捉到异常,然后尝试使用相同的光标执行另一个查询,我得到一个psycopg2.InternalError: current transaction aborted; ignoring actions until end of transaction block,或者类似的东西 这里是确切的错误消息:psycopg2.InternalError: current transaction is aborted, commands ignored until end of transaction block。插入表格失败后我该怎么做才能防止这种状态? 我试着在这里更有说服力地问这个问题:***.com/questions/3120688/…【参考方案2】:

我认为使用 EXISTS 更有效!你可以这样做:

if exists(select 1 from table_name where col1 = %s and col2 = %s) then
  insert into table_name (col1, col2, col3)
  select %s, %s, %s;
end if;

正在测试中,使用 EXISTS 比使用 NOT EXISTS 快大约 50 倍。

另一种方法是使用 EXCEPT 。

INSERT INTO table_name (col1, col2, col3)
SELECT %s, %s, %s
except
select col1, col2, col3 from table_name

正在测试中,使用 EXCEPT 比使用 NOT EXISTS 快大约 3 倍。

【讨论】:

以上是关于哪种 SQL 模式可以更快地避免插入重复行?的主要内容,如果未能解决你的问题,请参考以下文章

如何在更新和插入并发时避免重复行

JOINing多对多表时避免SQL查询中的重复行

在 SQL Server 视图中插入重复行

从 excel 导入数据时防止 SQL Server 2008 中的行重复

事务与批处理查询以避免重复的 MySQL 插入

Oracle SQL 多次插入忽略重复行