当前位置: 首页 > 面试题库 >

在唯一约束之前清理SQL数据

靳金鹏
2023-03-14
问题内容

我想在对两列施加唯一约束之前清理表中的某些数据。

CREATE TABLE test (
 a integer NOT NULL,
 b integer NOT NULL,
 c integer NOT NULL,
 CONSTRAINT a_pk PRIMARY KEY (a)
);

INSERT INTO test (a,b,c) VALUES
 (1,2,3)
,(2,2,3)
,(3,4,3)
,(4,4,4)
,(5,4,5)
,(6,4,4)
,(7,4,4);

-- SELECT a FROM test WHERE ????

输出应为2,6,7

我正在寻找重复 的第一之后的 所有行b,c

前任:

  • 第1,2行的(b,c)为(2,3)。第1行是正确的,因为它是第一个,第2行不是。

  • 行4,6,7的(b,c)为(4,4),行4可以,因为它是第一个,而6,7则不是。

然后,我将:

DELETE FROM test WHERE a = those IDs;

..并html" target="_blank">添加唯一约束。

我当时正在考虑与自身进行测试的交集,但不确定从哪里开始。


问题答案:

我进行了几次测试。EXISTS事实证明,该变体要快得多-
正如我预期的那样,与@Tometzky发布的相反。

使用窗口函数应该比这个答案快得多:

select a
from (
  select a, rank() over (partition by b, c order by a) as rank
  from test ) as _
where rank>1;

在PostgreSQL 9.1.2上以适当的设置测试10.000行的平台:

CREATE TEMP TABLE test (
  a serial
 ,b int NOT NULL
 ,c int NOT NULL
);

INSERT INTO test (b,c)
SELECT (random()* 100)::int AS b, (random()* 100)::int AS c
FROM   generate_series(1, 10000);

ALTER TABLE test ADD CONSTRAINT a_pk PRIMARY KEY (a);

在第一轮和第二轮测试之间,我进行了:

ANALYZE test;

当我最终应用DELETE时,删除了3368个重复项。如果您重复的次数太多或更少,性能可能会有所不同。

我与每个查询一起运行了几次,EXPLAIN ANALYZE并取得了最佳结果。通常,最佳与第一或最差没有什么不同。
裸露SELECT(不带DELETE)显示相似的结果。

1. CTE与 rank()

总运行时间:150.411毫秒
总运行时间:149.853毫秒-在分析之后

WITH x AS (
    SELECT a
          ,rank() OVER (PARTITION BY b, c ORDER BY a) AS rk
    FROM   test
    )
DELETE FROM test
USING  x
WHERE  x.a = test.a
AND    rk > 1;

2. CTE与 row_number()

总运行时间:148.240毫秒
总运行时间:147.711毫秒-进行分析后

WITH x AS (
    SELECT a
          ,row_number() OVER (PARTITION BY b, c ORDER BY a) AS rn
    FROM   test
    )
DELETE FROM test
USING  x
WHERE  x.a = test.a
AND    rn > 1;

3.row_number()在子查询中

总运行时间:134.753毫秒
总运行时间:134.298毫秒-在分析之后

DELETE FROM test
USING (
    SELECT a
          ,row_number() OVER (PARTITION BY b, c ORDER BY a) AS rn
    FROM   test
    )  x
WHERE  x.a = test.a
AND    rn > 1;

4.EXISTS半联接

总运行时间:143.777毫秒
总运行时间: 69.072毫秒 -进行分析后

DELETE FROM test t
WHERE EXISTS (
    SELECT 1
    FROM   test t1
    WHERE  t1.a < t.a
    AND   (t1.b, t1.c) = (t.b, t.c)
    );

第二轮的区别在于切换到 哈希半联接, 而不是附加的“ 排序+合并半联接”

结果

  • EXISTS 凭借最新的tp-date表统计信息显然可以胜出。
  • row_number()在子查询中使用过时的统计信息是最快的。
  • rank() 是最慢的变体。
  • CTE比子查询慢。
  • ANALYZE(更新的统计信息)有助于提高性能,并且 有所帮助。Autovacuum(默认值)应或多或少自动处理此问题-临时表或在对该表进行重大更改之后立即除外。

用100.000行进行测试

我用100.000行和63045重复重复了测试。相似的结果,只是EXISTS速度较慢,即使在以后也是如此ANALYZE

  1. 总运行时间:1648.601毫秒
  2. 总运行时间:1623.759毫秒
  3. 总运行时间:1568.893 ms
  4. 总运行时间:1692.249毫秒

将统计目标提高到1000,然后提高到最大10000(实际直播中的过度杀伤),另一个目标ANALYZE将所有查询的速度提高了约1%,但查询计划者仍选择使用
Sort + Merge Semi Join 作为EXISTS

ALTER TABLE test ALTER COLUMN b SET STATISTICS 10000;
ALTER TABLE test ALTER COLUMN c SET STATISTICS 10000;
ANALYZE test;

只有在我强迫计划程序避免合并联接之后,计划程序才使用 哈希半联接 再次花费了一半的时间:

SET enable_mergejoin = off
  1. 总运行时间:850.615毫秒

更新

从那时起,对查询计划器进行了 改进 。直接进入 Hash Semi Join 对PostgreSQL 9.1.7进行重新测试。



 类似资料:
  • 问题内容: 如何在Visual Studio中直观地在varchar(max)字段上创建唯一约束。 问题是当我尝试时: 管理索引和键 >添加>列 我只能选择bigint列,而不能选择任何varchar(max)列。 我是否可能必须使用 检查约束 ? 如果是,请在表达式中添加什么? Thnx的信息 问题答案: 您不能在列上设置唯一约束(最多2 GB的文本!)。您根本无法。 唯一性约束由后台中的唯一索

  • 主要内容:在创建表时设置唯一约束,在修改表时添加唯一约束,删除唯一约束MySQL 唯一约束(Unique Key)是指所有记录中字段的值不能重复出现。例如,为 id 字段加上唯一性约束后,每条记录的 id 值都是唯一的,不能出现重复的情况。如果其中一条记录的 id 值为‘0001’,那么该表中就不能出现另一条记录的 id 值也为‘0001’。 唯一约束与主键约束相似的是它们都可以确保列的唯一性。不同的是,唯一约束在一个表中可有多个,并且设置唯一约束的列允许有空值,但

  • 主要内容:Oracle唯一约束语法,Oracle唯一约束例子在本教程中,您将学习如何使用Oracle唯一约束来确保包含在一列或几列中的数据在表中的行之间是唯一的。 Oracle唯一约束语法 一个唯一的约束是一个完整性约束,它确保存储在一列或一组列中的数据在表中的行之间是唯一的。 通常,在使用内联约束语法创建表时,将唯一约束应用于列,如下所示: 此唯一约束指定中的值在整个表中是唯一的。也可以使用外线()约束语法来定义一个唯一的约束: 可以通过使用子句和约束名

  • 当我试图创建第二个表时,我遇到了以下错误,但我不知道为什么。对于表patente,我希望能够将(idfunconario,titulo)作为主键。正如其他主题中所建议的,我已经尝试将唯一约束设置为“唯一(IDFunconario,titulo)”。 消息错误: 错误:没有唯一的约束匹配引用表"public acao"的给定键SQL状态:42830 我在64位的Windows 8.1上使用Postg

  • 我有一个用户创建屏幕,它记录了各种用户详细信息以及名字和手机号码。我有一个对应的用户表,其中名字和手机号码构成一个复合唯一键。此表中还定义了其他完整性约束。 当在创建用户屏幕上输入违反此约束的用户数据时,需要向用户显示“用户友好”错误消息。 当这种违反发生时,我从MySQL数据库中得到的异常是: 有两个选项可以显示有意义的消息(例如:“错误:给定手机号码的用户名已存在,请更改其中一个”)。 选项1

  • 以下两者之间有区别吗: 以及: 在这两种情况下,名称是否唯一?索引唯一时意味着什么? 编辑:Postgres是唯一的约束,而索引没有回答我的问题。它考虑了FK的情况。我的问题与FK无关。我只想知道在这个例子中,这两个操作是否等价,其中不涉及FK。