从一个实例谈谈postgresql索引锁
最近客户在使用我司开发的数据库时,报告了如下问题(也不能算是问题,就是疑惑吧),环境如下:
OS : Red Hat Enterprise Linux Server release 6.7 (Santiago)
Kernel : 2.6.32-573.el6.x86_64
PostgreSQL : PostgreSQL 9.6.2
执行准备工作:
postgres=# create table test (id int, data text);
CREATE TABLE
postgres=# insert into test select a, 'Test data No ' || a from
generate_series(1,10000000) as a;
INSERT 0 10000000
postgres=# create index on test (id);
CREATE INDEX
postgres=# vacuum analyze verbose test;
......
然后,开启一个事务,在该事务中查询test表:
postgres=# begin ;
BEGIN
postgres=# select data from test where data = 'Test data No 1';
data
----------------
Test data No 1
(1 row)
在开另一个psql console,查询锁的情况:
postgres=# select c.oid, c.relname, l.locktype, l.pid, l.mode ,a.query
from (pg_class as c inner join pg_locks as l on (c.oid = l.relation))
inner join pg_stat_activity as a on (l.pid = a.pid) where relname like 'test%'
order by pid;
oid | relname | locktype | pid | mode |
query
-------+-------------+----------+-------+-----------------+----------
---
-------+-------------+----------+-------+-----------------+----------
---
-------+-------------+----------+-------+-----------------+----------
---
-------+-------------+----------+-------+-----------------+----------
---
-------+-------------+----------+-------+-----------------+--
19412 | test_id_idx | relation | 27612 | AccessShareLock | select data
from test where data = 'Test data No 1';
19405 | test | relation | 27612 | AccessShareLock | select
data from test where data = 'Test data No 1';
(2 rows)
发现在执行select期间对表上的所有的索引都加上了AccessShareLock锁,但是查询并没有走索引。这让客户非常奇怪。
没办法,带着这个问题调查了一番。大概有了以下的两点粗浅的认识和理解。
1.在执行一条select文时,数据库后端会对select文进行查询分析,查询重写,查询规划和查询执行四个阶段。在查询规划阶段,需要生成一个RelOptInfo结构存储优化的查询路径,该结构中存储了表上的索引信息。此处调用get_relation_info函数打开并锁定表上所有的索引,并将索引的信息写入到RelOptInfo结构体中。
具体到代码里,我们可以看到:
typedef struct RelOptInfo
{
NodeTag type;
RelOptKind reloptkind;
/* all relations included in this RelOptInfo */
Relids relids; /* set of base relids (rangetable indexes) */
.
.
.
List *indexlist; /* list of IndexOptInfo */ <------- here
.
.
.
bool has_eclass_joins; /* T means joininfo is incomplete */
} RelOptInfo;
这里indexlist就是查询的表上的所有的index的列表;
我们再看看get_relation_info函数,它获取该表上的“catalog information”,详情可以看看这段注释:
##############################################################
src/backend/optimizer/util/plancat.c:
/*
* get_relation_info -
* Retrieves catalog information for a given relation.
*
* Given the Oid of the relation, return the following info into fields
* of the RelOptInfo struct:
*
* min_attr lowest valid AttrNumber
* max_attr highest valid AttrNumber
* indexlist list of IndexOptInfos for relation's indexes
* serverid if it's a foreign table, the server OID
* fdwroutine if it's a foreign table, the FDW function pointers
* pages number of pages
* tuples number of tuples
*
* Also, initialize the attr_needed[] and attr_widths[] arrays. In most
* cases these are left as zeroes, but sometimes we need to compute attr
* widths here, and we may as well cache the results for costsize.c.
*
* If inhparent is true, all we need to do is set up the attr arrays:
* the RelOptInfo actually represents the appendrel formed by an inheritance
* tree, and so the parent rel's physical size and index information isn't
* important for it.
*/
void
get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
RelOptInfo *rel)
###################################################################
而由于该查询是放在一个事务中的,我们发现:
2.一个事务内申请的锁会在事务结束时调用函数LockReleaseAll统一释放,在事务结束之前,该事务仍然保持对锁的持有。
代码如下:
src/backend/storage/lmgr/lock.c:
/*
* LockRelease -- look up 'locktag' and release one 'lockmode' lock on it.
* Release a session lock if 'sessionLock' is true, else release a
* regular transaction lock.
*
* Side Effects: find any waiting processes that are now wakable,
* grant them their requested locks and awaken them.
* (We have to grant the lock here to avoid a race between
* the waking process and any new process to
* come along and request the lock.)
*/
bool
LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
最后我们打开lock log,再模拟下客户现场。贴一下执行结果:
postgres=# begin;
BEGIN
postgres=# select data from test where data = 'Test data No 1';
LOG: LockAcquire: lock [12373,16386] AccessShareLock at character 18
STATEMENT: select data from test where data = 'Test data No 1';
LOG: LockAcquire: lock [12373,16392] AccessShareLock
STATEMENT: select data from test where data = 'Test data No 1';
LOG: LockAcquire: lock [12373,16386] AccessShareLock
STATEMENT: select data from test where data = 'Test data No 1';
data
----------------
Test data No 1
(1 row)
postgres=# end;
LOG: LockReleaseAll: lockmethod=1
STATEMENT: end;
LOG: LockReleaseAll done
STATEMENT: end;
果然,锁是在事务最后释放的。
综合1,2两点,我们向客户解释了这个问题是PostgreSQL的式样,不是bug。
Over~
从一个实例谈谈postgresql索引锁的更多相关文章
- C#实现的内存分页机制的一个实例
C#实现的内存分页机制的一个实例 //多页索引表管理类(全局主索引表管理类) public class MuliPageIndexFeatureClass : IDisposable { protec ...
- 6. 将单独表空间(File-Per-Table Tablespaces)复制到另一个实例
6. 将单独表空间复制到另一个实例 本节介绍如何将单独表空间从一个MySQL实例复制 到另一个MySQL实例,也称为可传输表空间功能. 将InnoDB单独表空间复制到其他实例的原因有很多: - 在不对 ...
- Java程序只运行一个实例[转]
如果希望你的Java程序只能存在一个实例,可以参考下面的用法. 原文链接:http://blog.csdn.net/yaerfeng/article/details/7264729 Java没有提供这 ...
- PostgreSQL索引介绍
h1, h2, h3, h4, h5, h6, p, blockquote { margin: 5px; padding: 5; } body { font-family: "Helveti ...
- 事务(进程 ID 64)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。
访问频率比较高的app接口,在后台写的异常日志会偶尔出现以下错误. 事务(进程 ID 64)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品.请重新运行该事务 实所有的死锁最深层的原因就是一个 ...
- 从pg_hba.conf文件谈谈postgresql的连接认证
最近一直在弄postgresql的东西,搭建postgresql数据库集群环境什么的.操作数据库少不得要从远程主机访问数据库环境,例如数据库管理员的远程管理数据库,远程的客户存取数据库文件. 而在po ...
- C# 最基本的涉及模式(单例模式) C#种死锁:事务(进程 ID 112)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品。请重新运行该事务,解决方案: C#关闭应用程序时如何关闭子线程 C#中 ThreadStart和ParameterizedThreadStart区别
C# 最基本的涉及模式(单例模式) //密封,保证不能继承 public sealed class Xiaohouye { //私有的构造函数,保证外部不能实例化 private ...
- Postgresql 解决锁表
转载地址:https://blog.csdn.net/cicon/article/details/68068462##一.postgresql解决锁表--查询是否锁表了select oid from ...
- initdb - 创建一个新的 PostgreSQL数据库集群
SYNOPSIS initdb [ option...] --pgdata | -D directory DESCRIPTION 描述 initdb 创建一个新的 PostgreSQL 数据库集群. ...
随机推荐
- 第4章 同步控制 Synchronization ----互斥器(Mutexes)
Win32 的 Mutex 用途和 critical section 非常类似,但是它牺牲速度以增加弹性.或许你已经猜到了,mutex 是 MUTual EXclusion 的缩写.一个时间内只能够有 ...
- 实例讲解webpack的基本使用第二篇
这一篇来讲解一下如何设置webpack的配置文件webpack.config.js 我们新建一个webpack-demo的项目文件夹,然后安装webpack 执行如下命令 在项目文件夹下,建一个dis ...
- 关于 String 自我理解
String 的一些认识: String对象是不可变,所以使用 final 修饰 字符串拼接,合理利用 StringBuilder(线程非安全),StringBuffer 线程安全 常用方法就不详细介 ...
- validators配置要点及No result defined for action报错解决方案
在做JavaEE SSH项目时,接触到validators验证. 需要了解validators配置,或者遇到No result defined for action 这个错误时,可查阅本文得到有效解决 ...
- Tensorflow学习教程------创建图启动图
Tensorflow作为目前最热门的机器学习框架之一,受到了工业界和学界的热门追捧.以下几章教程将记录本人学习tensorflow的一些过程. 在tensorflow这个框架里,可以讲是若数据类型,也 ...
- 如何用Django从零开始搭建一个网站(0)
python,django等安装就直接略过了.下面直接奔如主题,搭建网站. Step1:新建一个django project,运行命令:‘django-admin startproject myPit ...
- Oracle之 any 、some、all解析
oracle之 any.some.all 解析 因为很少用到, 所以几乎忘记了这几个函数, 不过它们还是很有用的使用它们可以大大简化一些SQL文的语法, 至于效率问题, 如CCW所说它们和EXISTS ...
- Sqlserver中存储过程和游标的一些使用例子
/*带输入输出参数存储过程*/ ALTER PROCEDURE pro_test2 @userID INT, @maxUserID INT OUTPUT, @countUser INT OUTPUT ...
- 服务器cpu100%问题分析
ecs 130 : slb:
- NopCommerce 3. Controller 分析
1. 继承关系,3个abstract类 System.Web.Mvc.Controller Nop.Web.Framework.Controllers.BaseController Nop.Admin ...