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"]);
}

SQL Server递归代码超时

您正在耗尽可用的连接池,因为您正在为您解析的每个表达式和子表达式创建到数据库的连接,并且它们没有被及时清理以重新使用。

解决方案:不要递归地、迭代地或其他方式进行连接。为一个目的做一个,然后使用它。如果您需要及时释放连接以便重用它,请不要依赖类析构函数,因为当您希望它们运行时,它们不会运行。

一般来说,试图在其初始化器中隐式分配有限外部资源(如连接)的类应该是相当静态的对象,您当然不希望在打算像解析器那样动态创建对象的类中继承它们。

是否尝试延长超时时间?在连接字符串中添加一个大超时,如"连接超时=1800"。当我收到这样的消息时,这通常对我很有帮助。

您可以看到的另一件事是您是否可以进一步改进查询。

您可以检查数据库的最大连接设置。还要检查在新连接尝试开始超时时打开了多少活动连接。

如何确定ms sql server 2005中打开/活动连接的总数