KingbaseES V8R6 创建索引create index concurrently被阻塞
前言
CREATE INDEX CONCURRENTLY(CIC)是DBA们最常用的语句之一,它的好处是不阻塞DML语句。
但在大事务、长事务较多的系统,它可能被阻塞得很久。
本篇就从这个阻塞的案例开始,学习CIC的过程、原理以及注意事项。
测试CREATE INDEX CONCURRENTLY被阻塞
create table test(id int);
INSERT INTO test(id) VALUES (generate_series(1, 100000));
create table tmp(a int);
insert into tmp values(1);
会话1:
TEST=# select sys_backend_pid();
sys_backend_pid
-----------------
11860
(1 row)
select count(*) from test a, test b;
会话2:
create index concurrently ind_02 on tmp(a);
可以看到,即使test和tmp都不是同一个表,会话1执行的不是dml语句,tmp的索引创建依然被阻塞了。如果会话1中是要执行漫长的查询,会话2的索引创建也将一直被阻塞。
那么为什么被阻塞呢?
查看等待事件:
TEST=# SELECT pid, locktype,virtualxid,relation::regclass, mode FROM sys_locks where granted='f' order by pid;
pid | locktype | virtualxid | relation | mode
-------+------------+------------+----------+-----------
15150 | virtualxid | 6/5220 | | ShareLock
(1 row)
TEST=#
TEST=# SELECT pid, locktype,virtualxid,relation::regclass, mode FROM sys_locks where granted='t' order by pid;
pid | locktype | virtualxid | relation | mode
-------+------------+------------+-----------+--------------------------
11860 | relation | | test | AccessShareLock
11860 | virtualxid | 6/5220 | | ExclusiveLock
15150 | virtualxid | 7/1604 | | ExclusiveLock
15150 | relation | | tmp | ShareUpdateExclusiveLock
15440 | virtualxid | 8/659 | | ExclusiveLock
15440 | relation | | pg_locks | AccessShareLock
15440 | relation | | sys_locks | AccessShareLock
(7 rows)
当执行查询语句或dml时会获取一个virtualxid,但为什么创建索引要跟它获取同一个virtualxid?
先看看执行的函数堆栈,pid15150是被阻塞的pid,从堆栈中看到它正常获取一个锁WaitOnLock,锁类型是VirtualXactLock,并发现DefineIndex需要调用一个函数叫WaitForOlderSnapshots,它在等更旧的快照。
pid 15150:
gdb)
#0 0x00007f3f980917d3 in __epoll_wait_nocancel () from /lib64/libc.so.6
#1 0x00000000007f5ed3 in WaitEventSetWait ()
#2 0x00000000007f67b4 in WaitLatchOrSocket ()
#3 0x0000000000803ac5 in ProcSleep ()
#4 0x0000000000801362 in WaitOnLock ()
#5 0x0000000000802abf in LockAcquireExtended ()
#6 0x0000000000803242 in VirtualXactLock ()
#7 0x000000000062bd90 in WaitForOlderSnapshots ()
#8 0x000000000062fbf4 in DefineIndex ()
#9 0x000000000081ed29 in ProcessUtilitySlow ()
#10 0x000000000081f5ed in standard_ProcessUtility ()
#11 0x00007f3f909a95f9 in synonym_ProcessUtility () from /home/kingbase7/KESRealPro/V008R006C007B0012/Server/lib/synonym.so
#12 0x00007f3f907346a2 in plsql_utility_command () from /home/kingbase7/KESRealPro/V008R006C007B0012/Server/lib/plsql.so
#13 0x00007f3f8ffd70d4 in forceview_ProcessUtility () from /home/kingbase7/KESRealPro/V008R006C007B0012/Server/lib/force_view.so
#14 0x00007f3f8fdca8d6 in flashback_ProcessUtility () from /home/kingbase7/KESRealPro/V008R006C007B0012/Server/lib/kdb_flashback.so
#15 0x00007f3f8e73886b in pgss_ProcessUtility () from /home/kingbase7/KESRealPro/V008R006C007B0012/Server/lib/sys_stat_statements.so
#16 0x000000000081ac06 in PortalRunUtility ()
#17 0x000000000081c0bf in PortalRunMulti ()
#18 0x000000000081c979 in PortalRun ()
#19 0x00000000008174e2 in exec_simple_query ()
#20 0x000000000081a486 in PostgresMain ()
#21 0x000000000079fd2a in PostmasterMain ()
#22 0x00000000006eb5bf in main ()
pid 11860:
(gdb) bt
#0 0x00007f3f980917d3 in __epoll_wait_nocancel () from /lib64/libc.so.6
#1 0x00000000007f5ed3 in WaitEventSetWait ()
#2 0x00000000006da195 in secure_read ()
#3 0x00000000006e5824 in pq_recvbuf ()
#4 0x00000000006e5cb7 in pq_getbyte ()
#5 0x0000000000819a16 in PostgresMain ()
#6 0x000000000079fd2a in PostmasterMain ()
#7 0x00000000006eb5bf in main ()
可以看出进行select读操作,并获取buffer信息等,pq_getbyte描述了I/O读的操作。
sys_index表中的字段含义
indislive为true:表示索引可见,新事务知道这个索引存在。
indisready为true:表示该索引可写,新事务的DML操作需要维护该索引。
indisvalid 为true:表示改索引可读,新事务可以使用此索引进行查询。
CIC创建过程
阶段1
语法解析和预检查
构建catalog元数据信息, 主要包括 relcache,sys_class, sys_index,此时的状态是(indislive=true 索引可见、indisready=false不能被写入、indisvalid= false不能被查询)
获取一个锁(ShareUpdateExclusiveLock),避免创建阶段,表被删除。此阶段后,新事务会看到表中有一个invalid索引(但此时不可读写),
阶段2
1、获取ShareLock,等待此创建索引的表上所有的dml事务结束。
2、获取快照,对该表进行全表扫描,将对此快照可见的所有元组构建索引。
在这个阶段,其它事务对该表进行写入时,并不维护索引(因为索引还不能写入),仅保证HOT更新满足新索引定义,因此会有索引和表数据不一致的情况。
3、更新sys_index中indisready=true,此阶段后,索引可写入但不能查询(因为数据还不一致),其他事务修改该表时,需要维护新索引。
阶段3
第三阶段就是保证数据一致性。
使用ShareLock等待表上所有的dml事务结束,等待原因:阶段2中结束前开始的事务,无法看到新索引已变为可写状态,修改基表时并不维护新索引。
再次获取快照,进行一次全表扫描,将Phase2事务开始到现在索引中缺少的元组添加到索引中。
记下当前快照的xmin,获取所有早于当前快照xmin的快照的virtualxid,等待所有旧读写事务结束(我们的例子就卡在这步)
等待原因:旧事务的快照可以看到比构建索引时的快照更旧的行,如果它们使用新索引进行查询,会发生索引中查不到想要的旧数据,导致数据不一致。
因此,第3阶段必须等所有旧读写事务结束,才能将新索引置为可读状态。而后,更新relcache,释放锁ShareUpdateExclusiveLock。
CIC的注意事项
不要在有长事务时执行此操作,否则会等待很久。
CIC需要扫描两遍表,如果原表很大,耗时会更长,资源消耗更多。
分区表不支持在主表CIC创建索引,在子分区创建支持。
KingbaseES V8R6 创建索引create index concurrently被阻塞的更多相关文章
- MySQL 创建索引(Create Index)的方法和语法结构及例子
MySQL 创建索引(Create Index)的方法和语法结构及例子 MySQL 创建索引(Create Index)的方法和语法结构及例子 CREATE INDEX Syntax CREATE ...
- PostgreSQL的 create index concurrently
对于PostgreSQL的 "create index concurrently". 我个人认为其中存在一个bug. 我的验证过程如下: 我有两个表,tab01和 tab02,这两 ...
- SQL Server 创建索引(index)
索引的简介: 索引分为聚集索引和非聚集索引,数据库中的索引类似于一本书的目录,在一本书中通过目录可以快速找到你想要的信息,而不需要读完全书. 索引主要目的是提高了SQL Server系统的性能,加快数 ...
- Oracle常用操作——创建表空间、临时表空间、创建表分区、创建索引、锁表处理
摘要:Oracle数据库的库表常用操作:创建与添加表空间.临时表空间.创建表分区.创建索引.锁表处理 1.表空间 ■ 详细查看表空间使用状况,包括总大小,使用空间,使用率,剩余空间 --详细查看表空 ...
- SQL 创建索引的作用以及如何创建索引
SQL 创建索引的作用以及如何创建索引 SQL 创建索引的作用 一.使用索引的优点: 1.通过唯一性索引(unique)可确保数据的唯一性 2.加快数据的检索速度 3.加快表之间的连接 4.减少分组和 ...
- SQL创建索引和删除索引
使用CREATE 语句创建索引 CREATE INDEX index_name ON table_name(column_name,column_name) include(score) 普通索引 C ...
- Oracle数据库查看已添加的索引和创建索引
/** *查看目标表中已添加的索引 * */ --在数据库中查找表名 select * from user_tables where table_name like 'tablename%'; --查 ...
- Oracle创建索引;查询索引
1.创建索引 create index 索引名 on 表名(列名); 2.删除索引 drop index 索引名; 3.创建组合索引 create index 索引名 on 表名(列名1,,列名2); ...
- SQL语句-创建索引
语法:CREATE [索引类型] INDEX 索引名称ON 表名(列名)WITH FILLFACTOR = 填充因子值0~100 GO USE 库名GO IF EXISTS (SELECT * FRO ...
- SQLServer 语句-创建索引
语法:CREATE [索引类型] INDEX 索引名称ON 表名(列名)WITH FILLFACTOR = 填充因子值0~100GO /*实例*/USE 库名GOIF EXISTS (SELECT * ...
随机推荐
- Spring Security实现JDBC用户登录认证
在搭建博客后端服务框架时,我采用邮件注册+Spring Security登录认证方式,结合mysql数据库,给大家展示下具体是怎么整合的. 本篇是基于上一篇:spring boot实现邮箱验证码注册 ...
- Java集合框架学习(一)介绍
介绍 Java集合框架是一组接口和类的集合,它使得存储和处理数据更加有效率. 该框架有一些类,有很多函数使得程序员更加容易的处理集合类型数据. 后面的教程就是针对这些常用类展开,配合例子代码来给大家一 ...
- C#-SendKeys方法的使用
模拟键盘CTRL+S 的输入 using System; using System.Collections.Generic; using System.Diagnostics; using Syste ...
- js结合canvas画任意多边形
实现六边形 // html <canvas></canvas> // js const canvas = document.querySelector("canvas ...
- Program type already present: com.xxx
该错误是由于工程中存在着相同的类导致(包名与类名都相同),有可能是不同的依赖中有着相同的类,全局搜索该类便可得知
- 小程序开发:app.vue检测更新时判断是否是朋友圈进入
因为如果从朋友圈点进小程序来的,有些功能就用不了,所以需要判断下是否从朋友圈点进来的. 检查代码如下: checkScene() { // 判断场景值 如果是从分享到朋友圈再打开 就会有一些功能无法使 ...
- Java 客户信息管理软件 (面向对象 封装 总结)
1 package com.bytezero.cim.bean; 2 3 /** 4 * 5 * @Description Customer为实体对象,用来封装客户信息 6 * @author Byt ...
- 微信小程序开发:页面分享卡片、风格选择、通道启用等可配置
上文说到,我们部署了定时任务,但是有个地方忘记在上文写了,这里补上,就是定时任务的超时时间问题,超时时间有7200秒: 我们改成7100秒: 再把云函数调用的云对象的超时时间也改下: 超时时间多一点, ...
- Codeforces Round 770 (Div. 2)(数学异或奇偶性)
B. Fortune Telling 拿到题目看数据范围之后就知道暴力显然是来不及的. 那么只能找性质. \(考虑x和x+3的不同 \quad 奇偶性不同\) \(然后考虑两种操作对于一个数的奇偶性的 ...
- 你想要一个简单的 MQ 吗?(最简单的那种)
FolkMQ 一个简单的消息中间件(全球最简单的那种,要比谁都简单!).追世间简单为何物,可叫我生死相许! 面向简单编程 1) 启动服务 docker run -p 18602:18602 -p 86 ...