Oracle SQL 会话的生命周期是啥?
Posted
技术标签:
【中文标题】Oracle SQL 会话的生命周期是啥?【英文标题】:What is the lifecycle of a Oracle SQL session?Oracle SQL 会话的生命周期是什么? 【发布时间】:2019-12-19 14:27:35 【问题描述】:我在 Oracle SQL Server 中遇到了全局临时表的概念。根据tutorial on global temporary tables:
全局临时表中的数据是私有的,因此数据 由会话插入只能由该会话访问。
我相信这可能会出现以下情况:客户端启动存储过程两次,每次都预先用数据填充全局临时表以供 sp 处理。这两个计算不会相互干扰,因为每个计算都只看到自己的数据,而不是共享数据,就像使用常规表一样。
不过,这一切都取决于会话的构成,以及会话的开始和结束时间。
根据Oracle Database Concepts Glossary:
会话:数据库实例内存中的一个逻辑实体,表示当前用户登录到数据库的状态。一个 连接上可以建立 0、1 或更多会话。
连接:客户端进程和 Oracle 数据库实例之间的通信路径。
这并没有消除我所有的困惑,所以这是我的具体问题:
我的应用程序在其整个生命周期内都与 Oracle SQL 服务器保持单一连接。它在同一个连接上连续执行多个 SQL 命令/查询,这些查询中的每一个是它自己的会话,它们会共享一个会话,还是不是那么简单的回答?
考虑这个伪代码:
Command c1 = new Command("insert into TMP_TABLE (FOO) values ('TEST')");
Command c2 = new Command("select FOO from TMP_TABLE");
c1.Execute();
foreach (var value in c2.Query().Select("FOO"))
print(value);
我已经在我的应用程序中运行了上述命令,正如预期的那样,命令 c2
返回零结果。我认为这意味着每个查询都构成自己的会话,这就是我要寻找的。但我可以依赖它吗?
【问题讨论】:
【参考方案1】:Oracle SQL 会话的生命周期是什么?
会话是一个逻辑实体,从您的应用程序代码连接到数据库到断开连接之间存在。
会话独立于支持它们的物理(基于资源的)实体,例如连接、服务器进程、网络连接等。
在最简单(也是最常见的 imo)配置(即“专用服务器”)中,逻辑会话与物理连接和服务器进程之间存在 1-1 关系。在支持大量用户的更高级配置中,物理资源(连接、进程、网络资源)可以由多个会话共享/多路复用。
我已经在我的应用程序中运行了上述命令,并且正如预期的那样,命令 c2 返回了零结果。我认为这意味着每个查询都构成自己的会话
除非您的应用程序代码在调用之间断开或关闭/释放其连接,否则几乎可以肯定不是这种情况。
可以使用两个选项创建全局临时表:ON COMMIT DELETE ROWS
和 ON COMMIT PRESERVE ROWS
。
第一个将导致在 commit
或 rollback
上删除所有 GTT 数据。第二个将导致所有 GTT 数据在整个会话期间保持不变。
如果您没有使用ON COMMIT DELETE ROWS
,那么您应该不假设 GTT 在给定呼叫开始时为空。如果您要求在程序开始时 GTT 为空,则必须在程序开始时(或最后)DELETE FROM
您的 GTT(或 TRUNCATE
它)。
请注意,即使有此限制(即,必须自己在会话中清空 GTT),全局临时表仍然很有用,因为它们仍然可以保护一个会话不看到另一个会话的数据。与常规表相比,它们还编写了更少的重做,尤其是在 12.1 及更高版本中。事实上,从 Oracle 12.1 开始,它们根本不需要编写任何重做,这使得它们在只读和备用数据库中很有用。
除了...
我已经在我的应用程序中运行了上述命令,正如预期的那样,命令 c2 返回零结果
为此,您的 GTT 必须是使用 ON COMMIT DELETE ROWS
创建的,并且您的应用程序代码启用了某种“自动提交”功能,它会在每个 Command.Execute()
之后自动提交。否则你会误解/误报你的测试结果。
【讨论】:
【参考方案2】:我不知道您的应用程序是否在调用之间维护 Oracle 会话,但无论哪种方式,您都需要注意假设全局临时表 (GTT) 在第二次调用时将为空。因为如果它每次都获得一个“新”会话,那可能真正意味着您正在从连接池中获取一个免费会话。该会话的前一个用户(可能是您)可能已经为该会话填充了 GTT。我发现在使用基于 HTTP 的应用程序框架 Oracle Application Express (APEX) 时就是这种情况。
您需要调用使用 GTT 的 Oracle 存储过程,然后截断(清空)它(和/或在使用之前截断它),以确保每次都能获得干净的状态。
【讨论】:
【参考方案3】:Oracle 清除COMMIT/ROLLBACK
操作中的TEMPORARY
TABLE 内容。
因此,如果您的 Command 类在命令后发出 COMMIT
,它还将清除 temp
表中的数据,而 next
命令看不到任何内容。
【讨论】:
这不一定是真的 - 这取决于 GTT 是否是使用ON COMMIT DELETE ROWS
创建的。如果它是用它创建的,COMMIT 将清除 GTT 中的数据。但是,如果它是使用ON COMMIT PRESERVE ROWS
创建的,则数据将一直存在,直到会话关闭。使用共享会话,这就变成了一个问题 - 然后您需要在适当的时候手动删除数据。
谢谢 Boneist。从来没有真正考虑过在 ON COMMIT DELETE ROWS 之外使用 GTT 的可能性......至少这就是在两个命令之间丢失行是完全可以理解的。使用 ON COMMIT PRESERVE ROWS 选项,我相信 c2 不会空手而归。我是说。由于 c1 的提交(刷新)然后对 c2 使用不同的会话,c1 数据更容易丢失,这就是我试图传递的提示。【参考方案4】:
问题:“我的应用程序在其整个生命周期内都与 Oracle SQL 服务器保持单一连接。它在同一连接上连续执行多个 SQL 命令/查询,这些查询中的每一个是否都是其自己的会话,它们是否共享一个会话,还是不是这么简单的回答?”
如果这正是您描述的方式,那么每个查询都在其自己的CURSOR
而非会话中运行。如果您在会话上运行跟踪并查看原始跟踪文件,您将看到像 PARSING IN CURSOR
这样的部分,其中您的 SQL 被解析并检查语法和权限,然后是 EXEC
在服务器上执行的位置,然后是 @987654324 @ 将您的结果集提取到客户端,CLOSE
将光标关闭。如果您的查询已完成,您的光标将隐式关闭;但是通过 PL/SQL 和游标编程,您可以显式地控制/打开/关闭游标。隐式游标可以重复使用,因为 Oracle 在内部为每个游标分配了一个数字。即使您打开单个 SQL*Plus 连接并运行单个查询,oracle 也会为其分配一个游标。
例子:
PARSING IN CURSOR #18446744071393882224 len=51 dep=2 uid=63403 oct=3 lid=63403 tim=29425147118918 hv=682153908 ad='3e6edfd80' sqlid='344kggsnajpxn'
SELECT "BDD_EXTERNALBATCH_ID_SEQ".NEXTVAL FROM DUAL
END OF STMT
EXEC #18446744071393882224:c=73,e=73,p=0,cr=0,cu=0,mis=0,r=0,dep=2,og=1,plh=1849910378,tim=29425147118915
FETCH #18446744071393882224:c=9161,e=9402,p=0,cr=2,cu=3,mis=0,r=1,dep=2,og=1,plh=1849910378,tim=29425147128989
CLOSE #18446744071393882224:c=9,e=8,dep=2,type=3,tim=29425147129472
现在,例如,如果您通过 Weblogic 进行连接池 - 那么您将打开许多在连接池中定义的 SESSIONS,并且每个查询都会进入由 Weblogic 处理的相应会话。有时 Weblogic 会扩大或缩小池(在配置参数内),当池增长时,您将创建更多会话。
如果您选择这样做,您也可以在其自己的会话中运行每个查询,但这是一个非常糟糕的主意,并且出于性能原因无法扩展。最好在会话范围内或通过存储过程和包在服务器上运行尽可能多的查询和 DML。
关于 GTT(全局临时表) - 它们在您的会话中使用,并在您的会话关闭时释放。除了 GTT 的明显用途之外,我们还使用它们将某些类别的用户转移到不同的临时段(通过巧妙地使用视图和触发器),因为在繁忙的系统中,临时段的争用可能非常高。
【讨论】:
以上是关于Oracle SQL 会话的生命周期是啥?的主要内容,如果未能解决你的问题,请参考以下文章