检测 Oracle 连接泄漏的最佳方法?

The best way to detect Oracle connection leak?

一个用 C# Oracle 客户端编写的程序,证明有 "Connection leak" 它没有关闭所有数据库连接,因此一段时间后它无法再连接到数据库,因为打开的连接太多。

我编写了以下辅助函数(相当庞大):

        private static int tryFindConnCount(){
            var connstk = new Stack<Oracle.ManagedDataAccess.Client.OracleConnection>();
            try
            {
                for (var i = 0; i < 10000; ++i)
                {
                    var conn = new Oracle.ManagedDataAccess.Client.OracleConnection(
                        myDatabaseConnection);
                    conn.Open();
                    connstk.Push(conn);
                }                
            }
            catch(Exception e)
            {
                foreach (var conn in connstk)
                {
                    conn.Close();
                }

            }
            return connstk.Count;
        }

这是使用上述代码的测试用例中的代码:

            var co = tryFindConnCount();
            CodeThatMayLeakConnection();
            var cn = tryFindConnCount();

            Assert.That(cn, Is.EqaulTo(co));

它帮助我确定了至少一个存在连接泄漏的案例。

tryFindConnCount 的问题是它不应该在生产中使用。而且我认为应该有一些方法可以更便宜地获得相同的价值。

如何在代码中执行此操作以便在生产中监控此值?

您可以在 "gv$session" 视图上查询 Oracle 数据库以获取您需要的信息。通过对此视图的查询,您可以每 10-15 分钟循环监视一次数据库,以计算来自该程序的连接数。

下面的示例查询:

select count(*)
from gv$session
where machine = 'XXXXX'
and username = 'YYYYY'
and program = 'ZZZZZ';

您只需要唯一标识这些连接的值,例如发起连接的机器。

查询也很轻,不会增加性能开销。

试图找到连接未关闭的地方是一项艰巨的任务。

如果您离开程序并忘记关闭连接,最后执行的 sql 存储在 v$session 的列 SQL_ID 中(RAC 为 gv$session)。您可以在 v$session 中搜索 idle/dead 个会话。然后,您可以使用 v$sql 找到 SQL 文本,它可能会告诉您更多有关上次所做的事情。通过这个,您可能会得到在代码中搜索位置的提示。

select a.sid, a.username, a.program, a.machine, a.sql_id, b.sql_fulltext
  from v$session a, v$sql b
 where b.sql_id(+) = a.sql_id
   and a.username is not null  -- filter system processes, maybe filter more stuff
;