Oracle DBA最怕遇到CURSOR 相关的问题,如果发生了CURSOR争用导致的性能问题,是很难在短时间内分析清楚的。有时候我们重启数据库就解决了这个问题,不过有时候重启数据库后问题依然存在。幸运的是在PostgreSQL数据库中好像很少会遇到类似的问题,这是什么原因呢?
在一个高并发的系统中,SQL执行过程需要对SQL进行编译,这个过程无论哪种数据库都是必须有的。大体上分为语法语义解析、SQL REWRITE优化、执行计划生成、执行计划选择、执行等过程。在PostgreSQL中,可以用下面这个图来表示。
Oracle DBA最怕遇到CURSOR 相关的问题,如果发生了CURSOR争用导致的性能问题,是很难在短时间内分析清楚的。有时候我们重启数据库就解决了这个问题,不过有时候重启数据库后问题依然存在。幸运的是在PostgreSQL数据库中好像很少会遇到类似的问题,这是什么原因呢?
在一个高并发的系统中,SQL执行过程需要对SQL进行编译,这个过程无论哪种数据库都是必须有的。大体上分为语法语义解析、SQL REWRITE优化、执行计划生成、执行计划选择、执行等过程。在PostgreSQL中,可以用下面这个图来表示。
Oracle DBA最怕遇到CURSOR 相关的问题,如果发生了CURSOR争用导致的性能问题,是很难在短时间内分析清楚的。有时候我们重启数据库就解决了这个问题,不过有时候重启数据库后问题依然存在。幸运的是在PostgreSQL数据库中好像很少会遇到类似的问题,这是什么原因呢?
在一个高并发的系统中,SQL执行过程需要对SQL进行编译,这个过程无论哪种数据库都是必须有的。大体上分为语法语义解析、SQL REWRITE优化、执行计划生成、执行计划选择、执行等过程。在PostgreSQL中,可以用下面这个图来表示。
为了避免每次SQL执行之前都做上述昂贵的操作,Oracle构建了全局共享的CURSOR结构,用于在共享内存(SHARED POOL)中存储CURSOR共享部分的数据,用于所有的会话共享。似乎现在的Mysql、PostgreSQL等开源数据库和一些国产数据库都没有再采用这种全局共享CURSOR的机制,而大多数采用SQL不共享或者会话内共享CURSOR的机制,比如比较新版本的PostgreSQL就是采用会话内共享SQL的机制。
为什么Oracle使用全局CURSOR共享机制而PostgreSQL不使用呢?这实际上有两方面的原因,一个是历史原因,一个是商业原因。CURSOR共享在CPU资源不是很充裕的时代是相当有效提升RDBMS执行效率的手段,因为SQL解析是十分高开销的工作,能够一次编译多次执行,可以大大提高系统的并发执行性能。因此作为商用数据库的Oracle一直把提升CURSOR共享能力作为其核心竞争力,ORACLE的CURSOR全局共享就做成了一个独步天下的技术了。Postgresql这样的开源数据库没有Oracle的大手笔,因此选择了较为稳妥的会话内共享SQL的技术路线。幸亏是现在X86服务器技术的高速发展,CPU资源已经不是很难买到的了,因此不能在全局共享CURSOR的问题也已经不是一个特别严重的问题了。实际上,这些年我们遇到的因为CUSOR硬解析导致的ORACLE数据库性能问题也少了很多,主要原因是哪怕CURSOR解析使用了10+%的CPU资源,对我们的服务器来说也还是撑得住的。
虽然说PG并没有采用全局共享CURSOR的策略,不过在会话内共享多次执行的CURSOR仍然对PG数据库并发执行性能的提升有极大帮助的。说起共享CURSOR就不可避免地会聊到绑定变量的使用问题。使用绑定变量的好处是让SQL可以共享,可以让一条类似的SQL在多次执行中共享查询执行计划,这样就不需要每次都编译SQL语句;不过使用绑定变了也有缺点,在Oracle存在的著名的bind peeking问题在任何数据库中都会存在,因为绑定变量的差异可能选择不同执行计划才好的问题在很多时候都是存在的。在Oracle 9iR2之前,所有执行计划都是在变量绑定之前完成的,从9.2开始,Oracle将执行计划的生成放到了变量绑定之后,这样就让执行计划的生成更为精准了,不过这也带来了另外一个问题,那就是SQL第一次执行时的变量成为生成执行计划的依据,因此CURSOR共享会导致存在多种最优执行计划的SQL语句的运行性能变得不稳定。Oracle 11g之后的自适应CURSOR共享才基本上解决了这个问题。
PostgreSQL数据库的CURSOR共享机制学习了Oracle的这一个新的特性,采用了一种类似的方法来解决这个即共享CURSOR又尽可能避免多种最优执行计划导致的SQL性能问题,当然前提是,PostgreSQL的CURSOR共享是会话级的,不是实例级的。
在PostgreSQL的一个会话中,一条SQL的前五次执行,每次都会重新生成执行计划,这样就可以避免因为绑定变量的差异导致存在多种最优执行计划的问题无法被发现的问题出现。如果前五次编译发现存在通用执行计划,那么这个通用执行计划就会被共享。我们来看下面的例子。
为了避免每次SQL执行之前都做上述昂贵的操作,Oracle构建了全局共享的CURSOR结构,用于在共享内存(SHARED POOL)中存储CURSOR共享部分的数据,用于所有的会话共享。似乎现在的Mysql、PostgreSQL等开源数据库和一些国产数据库都没有再采用这种全局共享CURSOR的机制,而大多数采用SQL不共享或者会话内共享CURSOR的机制,比如比较新版本的PostgreSQL就是采用会话内共享SQL的机制。
为什么Oracle使用全局CURSOR共享机制而PostgreSQL不使用呢?这实际上有两方面的原因,一个是历史原因,一个是商业原因。CURSOR共享在CPU资源不是很充裕的时代是相当有效提升RDBMS执行效率的手段,因为SQL解析是十分高开销的工作,能够一次编译多次执行,可以大大提高系统的并发执行性能。因此作为商用数据库的Oracle一直把提升CURSOR共享能力作为其核心竞争力,ORACLE的CURSOR全局共享就做成了一个独步天下的技术了。Postgresql这样的开源数据库没有Oracle的大手笔,因此选择了较为稳妥的会话内共享SQL的技术路线。幸亏是现在X86服务器技术的高速发展,CPU资源已经不是很难买到的了,因此不能在全局共享CURSOR的问题也已经不是一个特别严重的问题了。实际上,这些年我们遇到的因为CUSOR硬解析导致的ORACLE数据库性能问题也少了很多,主要原因是哪怕CURSOR解析使用了10+%的CPU资源,对我们的服务器来说也还是撑得住的。
虽然说PG并没有采用全局共享CURSOR的策略,不过在会话内共享多次执行的CURSOR仍然对PG数据库并发执行性能的提升有极大帮助的。说起共享CURSOR就不可避免地会聊到绑定变量的使用问题。使用绑定变量的好处是让SQL可以共享,可以让一条类似的SQL在多次执行中共享查询执行计划,这样就不需要每次都编译SQL语句;不过使用绑定变了也有缺点,在Oracle存在的著名的bind peeking问题在任何数据库中都会存在,因为绑定变量的差异可能选择不同执行计划才好的问题在很多时候都是存在的。在Oracle 9iR2之前,所有执行计划都是在变量绑定之前完成的,从9.2开始,Oracle将执行计划的生成放到了变量绑定之后,这样就让执行计划的生成更为精准了,不过这也带来了另外一个问题,那就是SQL第一次执行时的变量成为生成执行计划的依据,因此CURSOR共享会导致存在多种最优执行计划的SQL语句的运行性能变得不稳定。Oracle 11g之后的自适应CURSOR共享才基本上解决了这个问题。
PostgreSQL数据库的CURSOR共享机制学习了Oracle的这一个新的特性,采用了一种类似的方法来解决这个即共享CURSOR又尽可能避免多种最优执行计划导致的SQL性能问题,当然前提是,PostgreSQL的CURSOR共享是会话级的,不是实例级的。
在PostgreSQL的一个会话中,一条SQL的前五次执行,每次都会重新生成执行计划,这样就可以避免因为绑定变量的差异导致存在多种最优执行计划的问题无法被发现的问题出现。如果前五次编译发现存在通用执行计划,那么这个通用执行计划就会被共享。我们来看下面的例子。
为了避免每次SQL执行之前都做上述昂贵的操作,Oracle构建了全局共享的CURSOR结构,用于在共享内存(SHARED POOL)中存储CURSOR共享部分的数据,用于所有的会话共享。似乎现在的Mysql、PostgreSQL等开源数据库和一些国产数据库都没有再采用这种全局共享CURSOR的机制,而大多数采用SQL不共享或者会话内共享CURSOR的机制,比如比较新版本的PostgreSQL就是采用会话内共享SQL的机制。
为什么Oracle使用全局CURSOR共享机制而PostgreSQL不使用呢?这实际上有两方面的原因,一个是历史原因,一个是商业原因。CURSOR共享在CPU资源不是很充裕的时代是相当有效提升RDBMS执行效率的手段,因为SQL解析是十分高开销的工作,能够一次编译多次执行,可以大大提高系统的并发执行性能。因此作为商用数据库的Oracle一直把提升CURSOR共享能力作为其核心竞争力,ORACLE的CURSOR全局共享就做成了一个独步天下的技术了。Postgresql这样的开源数据库没有Oracle的大手笔,因此选择了较为稳妥的会话内共享SQL的技术路线。幸亏是现在X86服务器技术的高速发展,CPU资源已经不是很难买到的了,因此不能在全局共享CURSOR的问题也已经不是一个特别严重的问题了。实际上,这些年我们遇到的因为CUSOR硬解析导致的ORACLE数据库性能问题也少了很多,主要原因是哪怕CURSOR解析使用了10+%的CPU资源,对我们的服务器来说也还是撑得住的。
虽然说PG并没有采用全局共享CURSOR的策略,不过在会话内共享多次执行的CURSOR仍然对PG数据库并发执行性能的提升有极大帮助的。说起共享CURSOR就不可避免地会聊到绑定变量的使用问题。使用绑定变量的好处是让SQL可以共享,可以让一条类似的SQL在多次执行中共享查询执行计划,这样就不需要每次都编译SQL语句;不过使用绑定变了也有缺点,在Oracle存在的著名的bind peeking问题在任何数据库中都会存在,因为绑定变量的差异可能选择不同执行计划才好的问题在很多时候都是存在的。在Oracle 9iR2之前,所有执行计划都是在变量绑定之前完成的,从9.2开始,Oracle将执行计划的生成放到了变量绑定之后,这样就让执行计划的生成更为精准了,不过这也带来了另外一个问题,那就是SQL第一次执行时的变量成为生成执行计划的依据,因此CURSOR共享会导致存在多种最优执行计划的SQL语句的运行性能变得不稳定。Oracle 11g之后的自适应CURSOR共享才基本上解决了这个问题。
PostgreSQL数据库的CURSOR共享机制学习了Oracle的这一个新的特性,采用了一种类似的方法来解决这个即共享CURSOR又尽可能避免多种最优执行计划导致的SQL性能问题,当然前提是,PostgreSQL的CURSOR共享是会话级的,不是实例级的。
在PostgreSQL的一个会话中,一条SQL的前五次执行,每次都会重新生成执行计划,这样就可以避免因为绑定变量的差异导致存在多种最优执行计划的问题无法被发现的问题出现。如果前五次编译发现存在通用执行计划,那么这个通用执行计划就会被共享。我们来看下面的例子。
作者:白鳝