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前檢查的,所以不會產生垃圾。
相關文章
- PostgreSQL唯一約束如何使用?SQL
- Oracle主鍵約束、唯一鍵約束、唯一索引的區別(轉)Oracle索引
- SQL Server唯一約束的使用SQLServer
- 【CONSTRAINT】具有唯一性約束的列是否可以插入空值AI
- Oracle唯一約束中NULL的處理OracleNull
- 【IMPDP】忽略匯入過程中違反約束的資料——DATA_OPTIONS引數
- 唯一性約束和唯一性索引的區別索引
- 履約產品:產品體系&履約監控產品搭建
- NULL和唯一約束UNIQUE的對應關係Null
- MySQL·捉蟲動態·唯一鍵約束失效MySql
- 【INDEX】Oracle中主鍵、唯一約束與唯一索引之區別IndexOracle索引
- PostgreSQL 原始碼解讀(4)- 插入資料#3(heap_insert)SQL原始碼
- 產品經理需要會寫程式碼嗎?
- 唯一索引操作可能產生的鎖索引
- 建立Oracle唯一約束,忽略已有的重複值Oracle
- MySQL 中的約束及相關操作MySql
- Mysql-基本練習(06-唯一約束、外來鍵約束、新增、刪除單列)MySql
- 你知道SQLite中有哪些約束嗎?SQLite
- 【SQL】15 SQL 約束(Constraints)、NOT NULL 約束、UNIQUE 約束、PRIMARY KEY 約束、FOREIGN KEY 約束、CHECK 約束、DEFAULT約束SQLAINull
- 預約直播|阿里雲CDP 產品釋出會阿里
- SQLite語句(一):表的操作和約束SQLite
- S008SELinux的約束操作Linux
- 唯一索引,可以在索引列插入多個null嗎索引Null
- 人工智慧包括約束求解器嗎?人工智慧
- 社群產品那點事兒 —— 垃圾帖與產品安全策略
- PostgreSQL11preview-支援陣列外來鍵約束SQLView陣列
- 【PK】Oracle 10g刪除主鍵約束後無法刪除唯一約束索引問題的模擬與分析Oracle 10g索引
- 約束你的git操作,讓你生無可戀。Git
- Javaweb-約束-外來鍵約束JavaWeb
- 查詢(看)表的主鍵、外來鍵、唯一性約束和索引索引
- Logical Standby中為什麼要求表中資料的唯一性約束
- 資料庫約束 主鍵-唯一性-Check-外來鍵資料庫
- 谷歌眼鏡更名Project Aura:未來會有新產品嗎谷歌Project
- 文字分析在收集產品反饋時的作用
- Oracle定義約束 外來鍵約束Oracle
- oracle中的約束Oracle
- Oracle - 約束、索引等相關常用操作語句Oracle索引
- 關於jvm的永久代會發生垃圾垃圾回收嗎?進來便知JVM