检测 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
;
一个用 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
;