postgresql-删除重复数据
在使用PG数据库的这段时间,总结了三种删除重复数据的方法,其中最容易想到的就是最常规的删除方法,但此方法性能较差,删数据耗时较久,虽容易实现,但性能太差,影响写数据的速率。
另外就是被使用的group by删除方法,效率较高。
还有一种是刚发现的,还没有验证,现在就总结下这三种删除方法,并验证各自的执行效率。
首先创建一张基础表,并插入一定量的重复数据。
test=# create table deltest(id int, name varchar(255));
CREATE TABLE
test=# create table deltest_bk (like deltest);
CREATE TABLE
test=# insert into deltest select generate_series(1, 10000), 'ZhangSan';
INSERT 0 10000
test=# insert into deltest select generate_series(1, 10000), 'ZhangSan';
INSERT 0 10000
test=# insert into deltest_bk select * from deltest;
1
2
3
4
5
6
7
8
9
常规删除方法
最容易想到的方法就是判断数据是否重复,对于重复的数据只保留ctid最小(或最大)的那条数据,删除其他的数据。
test=# explain analyse delete from deltest a where a.ctid <> (select min(t.ctid) from deltest t where a.id=t.id);
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
Delete on deltest a (cost=0.00..195616.30 rows=1518 width=6) (actual time=67758.866..67758.866 rows=0 loops=1)
-> Seq Scan on deltest a (cost=0.00..195616.30 rows=1518 width=6) (actual time=32896.517..67663.228 rows=10000 loops=1)
Filter: (ctid <> (SubPlan 1))
Rows Removed by Filter: 10000
SubPlan 1
-> Aggregate (cost=128.10..128.10 rows=1 width=6) (actual time=3.374..3.374 rows=1 loops=20000)
-> Seq Scan on deltest t (cost=0.00..128.07 rows=8 width=6) (actual time=0.831..3.344 rows=2 loops=20000)
Filter: (a.id = id)
Rows Removed by Filter: 19998
Total runtime: 67758.931 ms
test=# select count(*) from deltest;
count
-------
10000
(1 行记录)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
可以看到,id相同的数据,保留ctid最小的那条,其他的删除。相当于把deltest表中的数据删掉一半,耗时达到67s多。相当慢。
group by删除方法
第二种方法为group by方法,通过分组找到ctid最小的数据,然后删除其他数据。
test=# truncate table deltest;
TRUNCATE TABLE
test=# insert into deltest select * from deltest_bk;
INSERT 0 20000
test=# explain analyse delete from deltest a where a.ctid not in (select min(ctid) from deltest group by id);
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------
Delete on deltest a (cost=131.89..2930.46 rows=763 width=6) (actual time=30942.496..30942.496 rows=0 loops=1)
-> Seq Scan on deltest a (cost=131.89..2930.46 rows=763 width=6) (actual time=10186.296..30814.366 rows=10000 loops=1)
Filter: (NOT (SubPlan 1))
Rows Removed by Filter: 10000
SubPlan 1
-> Materialize (cost=131.89..134.89 rows=200 width=10) (actual time=0.001..0.471 rows=7500 loops=20000)
-> HashAggregate (cost=131.89..133.89 rows=200 width=10) (actual time=10.568..13.584 rows=10000 loops=1)
-> Seq Scan on deltest (cost=0.00..124.26 rows=1526 width=10) (actual time=0.006..3.829 rows=20000 loops=1)
Total runtime: 30942.819 ms
(9 行记录)
test=# select count(*) from deltest;
count
-------
10000
(1 行记录)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
可以看到同样是删除一半的数据,使用group by的方式,时间节省了一半。但仍含需要30s,下面试一下第三种删除操作。
新的删除方法
在postgres修炼之道这本书中,作者提到一种效率较高的删除方法, 在这里验证一下,具体如下:
test=# truncate table deltest;
TRUNCATE TABLE
test=# insert into deltest select * from deltest_bk;
INSERT 0 20000
test=# explain analyze delete from deltest a where a.ctid = any(array (select ctid from (select row_number() over (partition by id), ctid from deltest) t where t.row_number > 1));
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------
Delete on deltest a (cost=250.74..270.84 rows=10 width=6) (actual time=98.363..98.363 rows=0 loops=1)
InitPlan 1 (returns $0)
-> Subquery Scan on t (cost=204.95..250.73 rows=509 width=6) (actual time=29.446..47.867 rows=10000 loops=1)
Filter: (t.row_number > 1)
Rows Removed by Filter: 10000
-> WindowAgg (cost=204.95..231.66 rows=1526 width=10) (actual time=29.436..44.790 rows=20000 loops=1)
-> Sort (cost=204.95..208.77 rows=1526 width=10) (actual time=12.466..13.754 rows=20000 loops=1)
Sort Key: deltest.id
Sort Method: quicksort Memory: 1294kB
-> Seq Scan on deltest (cost=0.00..124.26 rows=1526 width=10) (actual time=0.021..5.110 rows=20000 loops=1)
-> Tid Scan on deltest a (cost=0.01..20.11 rows=10 width=6) (actual time=82.983..88.751 rows=10000 loops=1)
TID Cond: (ctid = ANY ($0))
Total runtime: 98.912 ms
(13 行记录)
test=# select count(*) from deltest;
count
-------
10000
(1 行记录)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
看到上述结果,真让我吃惊了一把,这么快的删除方法还是首次看到,自己真实孤陋寡闻,在这里要膜拜一下修炼之道这本书的大神作者了。
同时,努力向大神学习!!
---------------------
作者:arcticJian
来源:CSDN
原文:https://blog.csdn.net/arcticJian/article/details/50042647
版权声明:本文为博主原创文章,转载请附上博文链接!
postgresql-删除重复数据的更多相关文章
- sql查询删除重复数据
数据库UserInfo 删除重复数据 即删除重复的用户名手机号 同一个用户名手机号只保留一个用户 01.根据多个字段查询重复数据 with data1 as( select MobilePhone,N ...
- MYSQL删除重复数据
delete from co_jobinformation cwhere c.name in (select cc.name from co_jobinformation cc group by ...
- 取两个DataTable的交集,删除重复数据
/// <summary> /// 取两个DataTable的交集,删除重复数据 /// </summary> /// <param name="sourceD ...
- MSSQL如何在没有主键的表中删除重复数据
为了对重复数据进行实验,下面建一个设计不太好(没有主键)表并插入了一些重复数据: create database testdb use testdb ; go create table DupsNoP ...
- sql 删除重复数据且保留其中一条 用sql 关键字:with ROW_NUMBER
--1.建立表:Coursecreate table Course( ID int identity(1,1),--ID Student varchar(20) ,--学生 Sub varchar(2 ...
- mysql 删除重复数据,并保存最新一条数据
删除重复行 DELETE FROM ecm_member_login_session WHERE (number , client_code) IN ( ) AND update_time NOT I ...
- SQL语句删除重复数据
1.如表中没有主键,先添加自动增长主键 alter table 表名 add 列名 int identity (1,1) primary key 2.删除重复数据 delete from 表名 whe ...
- MySQL中删除重复数据的简单方法,mysql删除重复数据
MYSQL里有五百万数据,但大多是重复的,真实的就180万,于是想怎样把这些重复的数据搞出来,在网上找了一圈,好多是用NOT IN这样的代码,这样效率很低,自己琢磨组合了一下,找到一个高效的处理方式, ...
- Mysql开发技巧之删除重复数据
Mysql利用联表查询和分组来删除重复数据 //删除表中重复的id,保留最大的id mysql> select * from user; +----+------+ | id | name | ...
- T-SQL技术收集——删除重复数据
原文:T-SQL技术收集--删除重复数据 在工作和面试中,经常出现如何查询或者删除重复数据的问题,如果有主键,那还好办一点,如果没有主键,那就有点麻烦. 当一个表上没有辅助键时,如果使用SSMS界面来 ...
随机推荐
- Eclipse中创建一个新的SpringBoot项目
在Eclipse中创建一个新的spring Boot项目: 1. 首先在Eclipse中安装STS插件:在Eclipse主窗口中点击 Help -> Eclipse Marketplace... ...
- 安装php调试工具 Xdebug的步骤 火狐 phpstorm联调
一 安装服务器端 1 选择你的版本 <?php phpinfo(); ?> 比如我的: 关键是这三项:PHP Version 7.3.0Architecture x86 (x86是32位系 ...
- HTMLParser和BeautifulSoup使用入门和总结
1.HTMLParser一般这么用: from html.parser import HTMLParser from urllib import request class MyHtmlParser( ...
- 251. Flatten 2D Vector 平铺二维矩阵
[抄题]: Implement an iterator to flatten a 2d vector. Example: Input: 2d vector = [ [1,2], [3], [4,5,6 ...
- node.js 使用 net 模块模拟 websocket 握手,进行数据传递。
websocket 是一种让浏览器与服务器之间建立持久的连接,并能进行双向数据传输的一种协议. websocket 属性应用层协议,基于tcp传输协议,并复用http的握手通道. 一.如何进行webs ...
- 指定某个方法在站点的Application_Start之前执行
指定某个函数方法在站点的Application_Start之前执行:PreApplicationStartMethodAttribute 先预备一个类,用于Start时调用 public static ...
- linux命令-crontab
一.安装 yum install crontabs 二.基本使用 1.crontab -e:创建任务,进入编辑 格式: 基本格式 : ——————————————————— * * * * * com ...
- Minimum Domino Rotations For Equal Row LT1007
In a row of dominoes, A[i] and B[i] represent the top and bottom halves of the i-th domino. (A domi ...
- 深入理解JVM(二)Java内存区域
2.1 C.C++内存管理是由开发人员管理,而Java则交给了JVM进行自动管理 2.2 JVM运行时数据区:方法区.堆(运行时线程共享),虚拟机栈.本地方法栈.程序计数器(运行时线程隔离,私有) 1 ...
- Oracle学习——第一章
Oracle数据库特点:安全性高,数据类型丰富 Oracle是由美国甲骨文公司开发的一款数据库产品 -------------------------------------------------- ...