为什么用 PostgreSQL 绑定变量 没有 Oracle pin S 等待问题

早上看到盖国强老师在朋友圈里分享了一篇关于软解析带来的Pin S等待的问题。
有感而发,跟大家聊一聊为什么PostgreSQL不存在这个问题。

Oracle

在Oracle中多个会话高并发的执行同一条SQL,如果使用了绑定变量的话,会产生pin s的等待事件。
原因如下(取自互联网http://www.dbafree.net/?p=778)

每个child cursor(你可以认为是一条SQL的plan tree)下面都有一个mutexes这样的简单内存结构,当有session要执行该SQL而需要pin cursor操作的时候,session只需要以shared模式set这个内存位+1,表示session获得该mutex的shared mode lock.可以有很多session同时具有这个mutex的shared mode lock;
但在同一时间,只能有一个session在操作这个mutext +1或者-1。+1 -1的操作是排它性的原子操作。
如果因为session并行太多,而导致某个session在等待其他session的mutext +1/-1操作,则该session要等待cursor: pin S等待事件。

当看到系统有很多session等待cursor: pin S事件的时候,要么是CPU不够快,要么是某个SQL的并行执行次数太多了而导致在child cursor上的mutex操作争用。如果是硬件的问题,则可以升级硬件。

如果是SQL执行频率太高。最简单的做法是,将一条SQL拆分成多条SQL。增加SQL的版本数来降低并发。如一个SQL:

select name from acct where acctno=:1

可以改为如下4个SQL,则并发的争用可以下降4倍。

     select /A/ name from acct where acctno=:1
     select /B/ name from acct where acctno=:1
     select /C/ name from acct where acctno=:1
     select /D/ name from acct where acctno=:1

另外,我们还会经常碰到另外一个等待事件“cursor: pin S wait on X”,这个等待事件主要是由硬解析引起的,解释如下:

“cursor: pin S wait on X” wait event is mostly related to mutex and hard parse.
- When a process hard parses the SQL statement, it should acquire exclusive
library cache pin for the corresponding LCO.
- This means that the process acquires the mutex in exclusive mode.
- Another process which also executes the same query needs to acquire the mutex
but it’s being blocked by preceding process. The wait event is “cursor: pin S wait on X”.

cursor: pin S,
cursor: pin X,
cursor: pin S wait on X
这三个等待事件,实际上就是替代了cursor的library cache pin,
pin S代表执行(share pin),
pin X代表解析(exclusive pin),
pin S wait on X代表执行正在等待解析操作。
这里需要强调一下,它们只是替换了访问cursor的library cache pin,而对于访问procedure这种实体对象,依然是传统的library cache pin。
参考:
https://supporthtml.oracle.com/epmos/faces/ui/km/DocumentDisplay.jspx?_afrLoop=5051110464464000&id=1310764.1&_afrWindowMode=0&_adf.ctrl-state=fu77hl3v2_4
http://www.hellodb.net/2010/07/oracle-library-cache.html 这篇文章不错,每次看都能有所收获。

很显然,产生这个锁的客观原因是Oracle的plan tree结构是共享的,并且加锁是串行的,所以高并发的情况下就出问题了。
如果你的业务形态确实如此,就只能改客户端程序来避免类似的问题。

PostgreSQL

下面给大家分析一下为什么PostgreSQL不存在这个问题
原因也很简单,PostgreSQL的plan cache是会话级别的,会话之间不共享plan cache.
因此不存在Oracle pin S的问题。
例子:

postgres=# create table t(id int primary key);
CREATE TABLE
postgres=# insert into t select generate_series(1,100);
INSERT 0 100

.1. 使用绑定变量(pgbench -M prepared), 并发执行同一SQL

vi t.sql
\setrandom id 1 100
select * from t where id=:id;

pgbench -M prepared -n -r -f ./t.sql -c 64 -j 64 -T 120
tps = 1110129.983665 (including connections establishing)
tps = 1110693.523542 (excluding connections establishing)

23283.00  3.1% GetSnapshotData              /home/dege.zzz/pgsql9.6/bin/postgres
18074.00  2.4% AllocSetAlloc                /home/dege.zzz/pgsql9.6/bin/postgres
15403.00  2.1% LWLockAcquire                /home/dege.zzz/pgsql9.6/bin/postgres

Cpu(s): 72.2%us, 18.9%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  8.8%si,  0.0%st

.2. 使用绑定变量(pgbench -M prepared), 并发执行不同SQL

for ((i=1;i<=64;i++)); do sed  "s/select/select\ \/\ $i\ \//" t.sql >./t$i.sql ; done
生成
select / 1 / * from t where id=:id;
... ...
select / 64 / * from t where id=:id;

RUN
for ((i=1;i<=64;i++)); do pgbench -M prepared -n -r -f ./t$i.sql -c 1 -j 1 -T 120 | grep "^tps" & done

tps = 1089230.887 (including connections establishing)
tps = 1090257.658 (excluding connections establishing)

23272.00  3.0% GetSnapshotData              /home/dege.zzz/pgsql9.6/bin/postgres
17798.00  2.3% AllocSetAlloc                /home/dege.zzz/pgsql9.6/bin/postgres
15030.00  2.0% LWLockAcquire                /home/dege.zzz/pgsql9.6/bin/postgres

Cpu(s): 70.5%us, 18.0%sy,  0.0%ni,  2.9%id,  0.0%wa,  0.0%hi,  8.6%si,  0.0%st

可以看到他们的profile, 性能指标, CPU的分配,几乎都没有差异。
如果你原来是Oracle的用户,开发人员再也不用为pin S的问题妥协,放心大胆的用同一条SQL,随便绑。

时间: 2024-08-04 08:52:25

为什么用 PostgreSQL 绑定变量 没有 Oracle pin S 等待问题的相关文章

改写 sysbench oltp.lua 支持PostgreSQL绑定变量

源码在这里 https://github.com/digoal/sysbench_lua/tree/master/lua已经把oltp.lua改掉了,支持10条SQL,(有需要可以再自行调整)包括 但是由于sysbench不能识别execute语句,所以都算成了other query, 实际上就是这些使用了服务端绑定变量的query. 在一台普通的X86机器上测试了一下,15GB数据,跑以下SQL能达到47万QPS. -- select c from tbl where id = $1; --

让 sysbench 支持 PostgreSQL 服务端绑定变量

首先介绍一下几种数据库绑定变量的语义..1. PostgreSQL 绑定变量的语义是使用?来表示任意位置的变量, 例如 : select info from test where id=? and c1=?; .2. Oracle 使用:var来表示变量,例如: stmt = db_prepare("UPDATE ".. table_name .." SET k=k+1 WHERE id=to_number(:x) and 'a' = :y") params = {

Oracle绑定变量分级(Bind Graduation)

Oracle绑定变量分级(Bind Graduation) 绑定变量分级(Bind Graduation)是指Oracle在PL/SQL代码中会根据文本型绑定变量的定义长度而将这些文本型绑定变量分为四个等级,如下所示: l 定义长度小于等于32字节(Byte)的文本型绑定变量被分在第一个等级,Oracle为其分配32字节的内存空间. l 定义长度在[33,128]字节之间的被分在第二个等级,Oracle为其分配128字节的内存空间. l 定义长度在[129,2000]字节之间的文本型绑定变量被分

绑定变量优缺点、使用、绑定变量窥探、 Oracle自适应共享游标

绑定变量优缺点.使用.绑定变量窥探     绑定变量是Oracle解决硬解析的首要利器,能解决OLTP系统中library cache的过度耗用以提高性能.然刀子磨的太快,使起来锋利,却容易折断.凡事皆有利弊二性,因地制宜,因时制宜,全在如何权衡而已.本文讲述了绑定变量的使用方法,以及绑定变量的优缺点.使用场合.   一.绑定变量     提到绑定变量,就不得不了解硬解析与软解析.硬解析简言之即一条SQL语句没有被运行过,处于首次运行,则需要对其进行语法分析,语义识别,跟据统计信息生成最佳的执行

绑定变量及其优缺点

    绑定变量是Oracle解决硬解析的首要利器,能解决OLTP系统中library cache的过度耗用以提高性能.然刀子磨的太快,使起来锋利,却容 易折断.凡事皆有利弊二性,因地制宜,因时制宜,全在如何权衡而已.本文讲述了绑定变量的使用方法,以及绑定变量的优缺点.使用场合.   一.绑定变量     提到绑定变量,就不得不了解硬解析与软解析.硬解析简言之即一条SQL语句没有被运行过,处于首次运行,则需要对其进行语法分析,语 义识别,跟据统计信息生成最佳的执行计划,然后对其执行.而软解析呢,

一个执行计划异常变更的案例 - 外传之绑定变量窥探

上一篇文章<一个执行计划异常变更的案例 - 前传>(http://blog.csdn.net/bisal/article/details/53750586),介绍了一次执行计划异常变更的案例现象,这两天经过运行同事,以及罗大师的介绍,基本了解了其中的原因和处理方法,这个案例其实比较典型,涉及的知识点很多,有数据库新特性,有SQL相关的,还有应用数据质量问题,对于大师来说,是信手拈来的一次问题排查和处理,但至少对我这个仍旧艰难前行的初学者来说,值得回味的地方很丰富,所以有必要针对其中涉及的知识点

Oracle中如何绑定变量

oracle 中,对于一个提交的sql语句,存在两种可选的解析过程, 一种叫做硬解析,一种叫做软解析. 一个硬解析需要经解析,制定执行路径,优化访问计划等许多的步骤.硬解释不仅仅耗费大量的cpu,更重要的是会占据重要的们闩(latch)资源,严重的影响系统的规模的扩大(即限制了系统的并发行), 而且引起的问题不能通过增加内存条和cpu的数量来解决. 之所以这样是因为门闩是为了顺序访问以及修改一些内存区域而设置的,这些内存区域是不能被同时修改.当一个sql语句提交后,oracle会首先检查一下共享

oracle ORA-01745错误:无效的主机/绑定变量名

今天测试发现有个存储过程执行报ORA-01745: 无效的主机/绑定变量名的错误 报错语句是delete tbl_temp_01system where writetime > :sysdate 原来这个错误的原因是:sysdate这个绑定变量用了oracle关键字导致的. 将:sysdate改为:vsysdate,错误解决. 所以以后要主要绑定变量不能使用oracle关键字. 本文出自 "richard的笔记-积微成著" 博客,请务必保留此出处http://zxf261.blo

Oracle绑定变量与直方图

一.绑定变量的窥探(peek) 1.Oracle在处理带有绑定变量的SQL时候,只会在硬解析的时候才会"窥探"一下SQL中绑定变量的值,然后会根据窥探到的值来决定整个SQL的执行计划.参数:_optim_peek_user_binds  2.绑定变量窥探的案例 create table t8(id int ,name varchar2(100)); begin for i in 1 .. 1000 loop  insert into t8 values(i,'gyj'||i);  en