PostgreSQL 违反唯一约束的插入操作会产品HEAP垃圾吗?

PostgreSQL 是通过索引来保证唯一值约束的,(包括PKEY)。
但是,如果遇到唯一约束问题,HEAP和BTREE页里的数据会不会有垃圾呢?
SESSION A:
digoal=> create table pk_test(id int primary key);
CREATE TABLE
Time: 51.559 ms
digoal=> begin;
BEGIN
Time: 0.103 ms
digoal=> insert into pk_test values (1);
INSERT 0 1
Time: 0.565 ms

SESSION B:
digoal=> begin;
BEGIN
digoal=> insert into pk_test values (1);

SESSION C:
digoal=> begin;
BEGIN
digoal=> insert into pk_test values (1);

观察有无行锁:
显然没有,因为不是靠锁来保证唯一。而且插入也不需要行锁,因为未提交的记录其他会话是看不到的,也不可能来查询或更新,没有加锁的必要。
digoal=# create extension pgrowlocks;
CREATE EXTENSION
digoal=# select * from pgrowlocks('pk_test');
 locked_row | locker | multi | xids | modes | pids
------------+--------+-------+------+-------+------
(0 rows)

观察对象锁等待:
digoal=# create or replace function f_lock_level(i_mode text) returns int as $$
declare
begin
  case i_mode
    when 'INVALID' then return 0;
    when 'AccessShareLock' then return 1;
    when 'RowShareLock' then return 2;
    when 'RowExclusiveLock' then return 3;
    when 'ShareUpdateExclusiveLock' then return 4;
    when 'ShareLock' then return 5;
    when 'ShareRowExclusiveLock' then return 6;
    when 'ExclusiveLock' then return 7;
    when 'AccessExclusiveLock' then return 8;
    else return 0;
  end case;
end;
$$ language plpgsql strict;

digoal=# with t_wait as
(select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.objid,a.objsubid,
a.pid,a.virtualtransaction,a.virtualxid,a,transactionid,b.query,b.xact_start,b.query_start,
b.usename,b.datname from pg_locks a,pg_stat_activity b where a.pid=b.pid and not a.granted),
t_run as
(select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.objid,a.objsubid,
a.pid,a.virtualtransaction,a.virtualxid,a,transactionid,b.query,b.xact_start,b.query_start,
b.usename,b.datname from pg_locks a,pg_stat_activity b where a.pid=b.pid and a.granted)
select r.locktype,r.mode r_mode,r.usename r_user,r.datname r_db,r.relation::regclass,r.pid r_pid,
r.page r_page,r.tuple r_tuple,r.xact_start r_xact_start,r.query_start r_query_start,
now()-r.query_start r_locktime,r.query r_query,w.mode w_mode,w.pid w_pid,w.page w_page,
w.tuple w_tuple,w.xact_start w_xact_start,w.query_start w_query_start,
now()-w.query_start w_locktime,w.query w_query
from t_wait w,t_run r where
  r.locktype is not distinct from w.locktype and
  r.database is not distinct from w.database and
  r.relation is not distinct from w.relation and
  r.page is not distinct from w.page and
  r.tuple is not distinct from w.tuple and
  r.classid is not distinct from w.classid and
  r.objid is not distinct from w.objid and
  r.objsubid is not distinct from w.objsubid and
  r.transactionid is not distinct from w.transactionid and
  r.pid <> w.pid
  order by f_lock_level(w.mode)+f_lock_level(r.mode) desc,r.xact_start;
可以看到B,C会话正在等待transactionid锁,是由于约束检测造成的。
-[ RECORD 1 ]-+--------------------------------
locktype      | transactionid
r_mode        | ExclusiveLock
r_user        | digoal
r_db          | digoal
relation      |
r_pid         | 24785
r_page        |
r_tuple       |
r_xact_start  | 2015-06-04 12:27:53.475664+08
r_query_start | 2015-06-04 12:28:00.13671+08
r_locktime    | 00:00:43.79604
r_query       | insert into pk_test values (1);
w_mode        | ShareLock
w_pid         | 7536
w_page        |
w_tuple       |
w_xact_start  | 2015-06-04 12:28:19.256706+08
w_query_start | 2015-06-04 12:28:21.89269+08
w_locktime    | 00:00:22.04006
w_query       | insert into pk_test values (1);
-[ RECORD 2 ]-+--------------------------------
locktype      | transactionid
r_mode        | ExclusiveLock
r_user        | digoal
r_db          | digoal
relation      |
r_pid         | 24785
r_page        |
r_tuple       |
r_xact_start  | 2015-06-04 12:27:53.475664+08
r_query_start | 2015-06-04 12:28:00.13671+08
r_locktime    | 00:00:43.79604
r_query       | insert into pk_test values (1);
w_mode        | ShareLock
w_pid         | 7411
w_page        |
w_tuple       |
w_xact_start  | 2015-06-04 12:28:10.211724+08
w_query_start | 2015-06-04 12:28:12.188666+08
w_locktime    | 00:00:31.744084
w_query       | insert into pk_test values (1);
结束会话a, B,C报错。
SESSION A:
digoal=> end;
COMMIT
Time: 0.235 ms

SESSION B:
ERROR:  duplicate key value violates unique constraint "pk_test_pkey"
DETAIL:  Key (id)=(1) already exists.

SESSION C:
ERROR:  duplicate key value violates unique constraint "pk_test_pkey"
DETAIL:  Key (id)=(1) already exists.

接下来要观察, session b,c到底有没有将记录插进去,从ctid可以看到B,C的两条未提交的垃圾记录已经插入了heap page。
所以需要垃圾回收。
digoal=> insert into pk_test values(2);
INSERT 0 1
digoal=> select ctid,* from pk_test ;
 ctid  | id
-------+----
 (0,1) |  1
 (0,4) |  2
(2 rows)

但是index page是没有被插入的,因为这个INDEX就是保证唯一性的,不可能在这里出现重复。
digoal=# create extension pageinspect;
CREATE EXTENSION
digoal=# select * from bt_page_items('digoal.pk_test_pkey',1);
 itemoffset | ctid  | itemlen | nulls | vars |          data
------------+-------+---------+-------+------+-------------------------
          1 | (0,1) |      16 | f     | f    | 01 00 00 00 00 00 00 00
          2 | (0,4) |      16 | f     | f    | 02 00 00 00 00 00 00 00
(2 rows)

接下来我们看看check约束,会不会造成垃圾数据?
digoal=> create table ck_test(id int check (id>10));
CREATE TABLE
digoal=> insert into ck_test values (1);
ERROR:  new row for relation "ck_test" violates check constraint "ck_test_id_check"
DETAIL:  Failing row contains (1).
digoal=> insert into ck_test values (11);
INSERT 0 1
digoal=> select ctid,* from ck_test ;
 ctid  | id
-------+----
 (0,1) | 11
(1 row)

digoal=> insert into ck_test values (1);
ERROR:  new row for relation "ck_test" violates check constraint "ck_test_id_check"
DETAIL:  Failing row contains (1).
digoal=> insert into ck_test values (1);
ERROR:  new row for relation "ck_test" violates check constraint "ck_test_id_check"
DETAIL:  Failing row contains (1).
digoal=> insert into ck_test values (11);
INSERT 0 1
digoal=> select ctid,* from ck_test ;
 ctid  | id
-------+----
 (0,1) | 11
 (0,2) | 11
(2 rows)
从ctid可以看到,check约束是在数据进入heap page前检查的,所以不会产生垃圾。
时间: 2024-10-25 01:08:02

PostgreSQL 违反唯一约束的插入操作会产品HEAP垃圾吗?的相关文章

异常信息乱码-ssh框架;事务配置在service层,批量插入时违反唯一约束;返回的异常信息中有乱码 如下

问题描述 ssh框架:事务配置在service层,批量插入时违反唯一约束:返回的异常信息中有乱码 如下 org.springframework.dao.DataIntegrityViolationException: Duplicate entry '?-?R' for key 'num'; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException:

hibernate 进行插入操作的时候部分数据 出现索引唯一约束的问题

问题描述 hibernate 进行插入操作的时候部分数据 出现索引唯一约束的问题 现在我想在进行插入数据之前删掉 相关索引,求高手指导hibernate 怎么清除指定索引,或者用其他方法解决这个问题 解决方案 用hibernate 直接执行sql drop index XXX

PostgreSQL 另类advisory lock保证唯一约束法

在没有唯一约束或者主键约束时,数据库是不保证唯一性的.那么有什么手段来保证呢? 方法 1. 串行操作,先查询,如果没有查到记录,则插入. 这种方法效率非常低: 测试如下: postgres=# create table tbl(c1 text); CREATE TABLE postgres=# create index idx_c1 on tbl(c1); CREATE INDEX postgres=# create or replace function load(v_c1 text) ret

hibernate-Hibernate:用saveOrUpdate报违反主键唯一约束

问题描述 Hibernate:用saveOrUpdate报违反主键唯一约束 用saveOrUpdate往表里面插入数据,结果抛出异常报违反主键唯一: org.hibernate.exception.ConstraintViolationException: Duplicate entry '1-2015-11-02' for key 'PRIMARY' at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQL

Oracle中唯一约束和唯一索引的区别

在使用TOAD来操作Oracle数据库时,会注意到创建约束时有Primary Key.Check.Unique和Foreign Key四种类型的约束,这与SQL Server中的约束没有什么区别,这里的Check约束除了用于一般的Check约束外,在Oracle中也用于非空约束的实现.也就是说如果一个字段不允许为空,则系统将会创建一个系统的Check约束,该约束定了某字段不能为空. 除了约束,还有另外一个概念是索引,在TOAD中创建索引的界面如下: 我们可以注意到在唯一性组中有三个选项:不唯一.

急:SSH+Oracle||用hibernate进行多对多关系映射 出错 违反唯一性约束 奇怪

问题描述 Oracle 9i,使用hibernate,多对多的关系映射,级联操作的时候,出错了.我的数据库中表的主键是采用自增长的方式,序列+触发器进行的自增长.实体类与表的映射文件,如下<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.s

创建可编辑的xml文档(之四) 删除、改名、插入操作

xml|插入|创建 执行删除.改名.插入操作   实现了拖放操作就已经完了最难的部分,但是出于完整性考虑,还应该提供一些更好的基本的编辑功能. 下面仅仅用四行代码就可以实现删除操作:   重命名操作需要更多的一些考虑,你可以调用   最后一个挑战就是如何按照需求创建一个新的文件夹.         insert_fragment.DocumentElement treeview 控件可以缓存一个结构的副本,将它作为一个临时变量来创建一个新的文件夹集合.你所要做的仅仅是确保被定义得文件夹可以被  

ORACLE空间管理实验(六)块管理之ASSM下插入操作

高水位的影响及大并发插入的性能问题 一.数据块的插入时寻找可用块的规则总结: 高水位与低高水位:低高水位与高水位之间存在的数据块的状态可能是未格式化或格式的.低高水位以下的是格式化了的,可以被使用. 1.首先,插入一条数据,只会使用高水位以下的数据块. 高水点的位置:L1块所包含数据块的边界,要么是区的边界 2.第一次插入一行数据,格式化块数? 并没有一个一定的数值,从DUMP L1块中看,有格式化5个,32个64个等. 3.插入一行数据,如何通过L3-->L2-->L1--数据块,这个过程来

mysql-QT连MySQL数据库插入操作问题

问题描述 QT连MySQL数据库插入操作问题 版本:QT5.2.1 MySQL5.0代码如下: 代码一:query.exec(""insert into text1(idnamesex) values(1'1''1')""); 给数据库中text1表中插入数据,成功! 代码二:query.prepare(""insert into text1(idnamesex)""""values(:id:name:se