SQL Server递归代码超时
本文关键字:超时 代码 递归 Server SQL | 更新日期: 2023-09-27 18:18:21
我有一个实现数据库连接的基类。我有第二个继承这个基数据库类的类。第二个类内部有一些递归,当计算它的值时,它可能实例化第二个类的另一个实例。递归的深度只有几层。我在单线程运行所有东西。
我的代码将正确运行大约1或2分钟,然后我开始得到一致的错误:"超时过期。
从连接池中获取连接之前的超时时间。我的基类有一个析构函数,它调用数据库对象的。dispose()方法。第二个类有一个析构函数,用于关闭基类中的连接对象。
我到数据库的连接字符串指定了连接超时= 0。
任何想法,为什么代码将正常工作几分钟,然后开始超时尝试连接到数据库?我困惑。
namespace BaseLib2
{
public class TSBase
{
protected StreamWriter logFile;
protected OleDbCommand queryCmd;
protected OleDbCommand exeCmd;
protected OleDbConnection connection;
protected OleDbDataReader reader;
public SqlConnection sqlconn;//used for BCP
public TSBase()
{
}
~TSBase()
{
try
{
queryCmd.Dispose();
exeCmd.Dispose();
reader.Dispose();
connection.Dispose();
sqlconn.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("BaseLib2 destrutor:" + ex.Message);
}
}
public void ConnectToDB()
{
string connString = "Provider=SQLNCLI11;Server=myserver;Database=mydb;Uid=myid;pwd=password;connection timeout=0";
queryCmd = new OleDbCommand();
exeCmd = new OleDbCommand();
connection = new OleDbConnection(connString);
queryCmd.CommandTimeout = 60000;
exeCmd.CommandTimeout = 60000;
connection.Open();
queryCmd.Connection = connection;
exeCmd.Connection = connection;
string sqlConnString = "server=dc2k8housql;database=mydb;Uid=myid;pwd=password;connection timeout=0";
sqlconn = new SqlConnection(sqlConnString);
sqlconn.Open();
}
public class Expression : BaseLib2.TSBase
{
private string ExpName;
private string ExpressionTxt;
private string sql;
private DateTime Contract_dt;
private DateTime Quote_dt;
private bool SaveToDB;
private string BaseSymbol;
public Expression(string expNameIn, DateTime contract_dtIn, DateTime quote_dtIn)
{
ExpName = expNameIn;
Contract_dt = contract_dtIn;
Quote_dt = quote_dtIn;
try
{
try
{
ConnectToDB();
}
catch (Exception ex)
{
Console.WriteLine("Error in EXP constructor connecting to database." + ex.Message );
throw new Exception("Error in EXP constructor connecting to database.");
}
//get expression text from database
sql = "select expression, save_to_db, coalesce(base_symbol, '') as base_symbol from expressions where exp_name = " + DBI(ExpName);
reader = ReadData(sql);
if (reader.Read())//should only return 1 row
{
ExpressionTxt = reader[0].ToString();
SaveToDB = bool.Parse(reader[1].ToString());
BaseSymbol = reader[2].ToString();
}
reader.Close();
}
catch (Exception ex)
{
Console.WriteLine("Exception in Expression constructor:" + ex.Message);
}
}
~Expression()
{
try
{
connection.Close();
sqlconn.Close();
connection.Dispose();
sqlconn.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("Error in destructor:" + ex.Message);
}
}
public double Eval()
{
try
{
//check to see if there are any $RV in the expression
if (ExpressionTxt.Contains("$RV("))
{
//parse and evaluate the $RV's
String[] split = ExpressionTxt.Split(("$".ToCharArray()));
foreach (string s in split){
Console.WriteLine("s=" + s);
if (s.Length > 3)//make sure we have a string with a symbol in it
{
//for each rv we find, create a new expression and evaluate it
if (s.Substring(0, 3).Contains("RV"))
{
int pStart = s.IndexOf("(");
int pEnd = s.IndexOf(")");
string rvSymb = s.Substring(pStart + 1, pEnd - pStart - 1);
System.Console.WriteLine(rvSymb);
Expression oExp = new Expression(rvSymb, Contract_dt, Quote_dt);
double rVal = oExp.Eval();//recursive call
oExp = null;
ExpressionTxt = ExpressionTxt.Replace("$RV(" + rvSymb + ")", rVal.ToString());
}
}
}
}
//replace SV values in formula
if (ExpressionTxt.Contains("$SV("))
{
//find symbols in $SV brackets and collect contract dates
String[] split = ExpressionTxt.Split (("$".ToCharArray()));
foreach (string s in split)
{
if (s.Length > 3)
{//make sure we have a symbol
if (s.Substring(0, 3).Contains("SV"))
{
int pStart = s.IndexOf("(");
int pEnd = s.IndexOf(")");
string svSymb = s.Substring(pStart + 1, pEnd - pStart - 1);
System.Console.WriteLine("sv=" + svSymb);
//replace $SV with numerical values
double sVal = GetQuoteValue(svSymb);
ExpressionTxt = ExpressionTxt.Replace("$SV(" + svSymb + ")", sVal.ToString());
}
}
}
}
//evaluate
double ret = Evaluate(ExpressionTxt);
Console.WriteLine(ExpName + "=" + ret.ToString());
if (SaveToDB)
{
Console.WriteLine(ExpName + " cd:" + Contract_dt.ToShortDateString() + " qd:" + Quote_dt.ToShortDateString() + ": saving to db...");
sql = "delete from exp_quotes where exp_name = " + DBI(ExpName ) ;
sql = sql + " and contract_dt = " + DBI(Contract_dt.ToShortDateString());
sql = sql + " and quote_dt = " + DBI(Quote_dt.ToShortDateString());
WriteData(sql);
sql = "insert into exp_quotes(exp_name, contract_dt, quote_dt, calculated_dt, price) values(";
sql = sql + DBI(ExpName ) + "," + DBI(Contract_dt.ToShortDateString()) + "," + DBI(Quote_dt.ToShortDateString());
sql = sql + ", getdate(), " + ret + ")";
WriteData(sql);
}
connection.Close();//after we evaluate, close down the connection
connection.Dispose();
return ret;
//return value
}
catch (Exception ex)
{
Console.WriteLine("exp:" + ExpName + " cd:" + Contract_dt.ToShortDateString() + " qd:" + Quote_dt.ToShortDateString() + " = " + ex.Message);
}
return 0;
}
private double GetQuoteValue(string symbIn)
{
double ret = 0;
sql = "select close_val from prices_union_all_vw where symbol = " + DBI(symbIn) + " and contract_dt = " + DBI(Contract_dt.ToShortDateString()) + " and quote_dt = " + DBI(Quote_dt.ToShortDateString());
reader = ReadData(sql);
if (reader.Read())
{
ret = Double.Parse(reader[0].ToString());
reader.Close();
}
else
{//we didn't get a record for the specific quote date, try again using the mostrecent view
sql = "select close_val from prices_union_all_mostrecent_vw where symbol = " + DBI(symbIn) + " and contract_dt = " + DBI(Contract_dt.ToShortDateString());
reader = ReadData(sql);
if (reader.Read())
{
ret = Double.Parse(reader[0].ToString());
}
reader.Close();
}
return ret;
}
private static double Evaluate(string expression)
{
var loDataTable = new DataTable();
var loDataColumn = new DataColumn("Eval", typeof(double), expression);
loDataTable.Columns.Add(loDataColumn);
loDataTable.Rows.Add(0);
return (double)(loDataTable.Rows[0]["Eval"]);
}
您正在耗尽可用的连接池,因为您正在为您解析的每个表达式和子表达式创建到数据库的连接,并且它们没有被及时清理以重新使用。
解决方案:不要递归地、迭代地或其他方式进行连接。为一个目的做一个,然后使用它。如果您需要及时释放连接以便重用它,请不要依赖类析构函数,因为当您希望它们运行时,它们不会运行。
一般来说,试图在其初始化器中隐式分配有限外部资源(如连接)的类应该是相当静态的对象,您当然不希望在打算像解析器那样动态创建对象的类中继承它们。
是否尝试延长超时时间?在连接字符串中添加一个大超时,如"连接超时=1800"。当我收到这样的消息时,这通常对我很有帮助。
您可以看到的另一件事是您是否可以进一步改进查询。
您可以检查数据库的最大连接设置。还要检查在新连接尝试开始超时时打开了多少活动连接。
如何确定ms sql server 2005中打开/活动连接的总数