PDA

View Full Version : محدودیت های مختلف در کانکشن sql server 2008 در C#‎



sajadf7
چهارشنبه 23 فروردین 1396, 18:21 عصر
سلام و عرض ادب
من یک برنامه نوشتم که توش از sql server 2008 برای مدیریت اطلاعاتم استفاده میکنم.

یک نرم افزار هست که هزاران thread رو اجرا میکنه و داخل ترد ها روی رکورد های sql ویرایش یا اینسرت و یا ... انجام میشه.

من وقتی برای هر کویری یک کانکشن باز میکنم و بعد از اتمام کارش کانکشن رو میبندم خطای تعداد کانکشن ها که از سمت پولینگ هست میاد و عملا تعداد کانکشن ها رو کم میاره

اومدم کل برنامه رو با یک کانکشن وصل کردم به صورت عمومی. بعد تو رشته اتصال اینم اضافه کردم برای ارسال همزمان کویری ها به سرور :

Data Source = localhost;database=TaskQueue;Persist Security Info=True;integrated security=SSPI; MultipleActiveResultSets=true;Connection Timeout=0

تو این حالت مشکلی پیش نمیاد تا زمانی که حدود 15 هزار ترد در حال اجرا هستند و بعد از رسیدن به یک تعداد حدودی 10 هزار ترد برنامه گیر میکنه.
خطا میده که

Timeout expired.
The timeout period elapsed prior to completion of the operation or the server is not responding.

اومدم برای حل این مشکل هم برای هر کامند تایم اوت رو غیر فعال کردم به این شکل :
command.CommandTimeout = 0;

الان وقتی یکم برنامه اجرا شد و تعداد ریکویست های sql زیاد شد کل برنامه دیگه گیر میکنه و هیچ query رو به sql server نمیفرسته

حتی وقتی sql server studio managment رو باز میکنم و از داخل اون یک query مینویسم گیر میکنه و یک count ساده که مینویسم حدودا یکو نیم ساعت و یا بیشتر طول میکشه جواب بده بهم.

ممنون میشم راهنمایی کنید برای حل این مشکل

danialafshari
پنج شنبه 24 فروردین 1396, 04:09 صبح
با سلام
هیچ کد و یا بانکی رو قرار ندادید تا بررسی بشه
قبل از طراحی بهتر بود سوال میپرسیدید ممکن بود نیازی به این همه ترد نبود و Stored Procedure ها کارتون رو راه مینداختن
اگر در sql management هم نمیتونید query برگردونید احتمالا ویندوز مشکل پیدا کرده باشه بهتر بود بانکتون رو قرار میدادید تا دوستان بررسی کنن
موفق باشید

sajadf7
جمعه 25 فروردین 1396, 14:32 عصر
ببینید یک تابع به این صورت دارم :
public void CheckDatabaseForTasks()
{
while (true)
{
Thread.Sleep(15000);

SqlConnection connection = new SqlConnection(Assist.connectionString);

SqlDataReader rdr = null;
string Server = "", Account = "", Password = "";
try
{
connection.Open();
SqlCommand cmd = new SqlCommand("select * from UpgradeQueue where dateend < convert(datetime,'" + DateTime.Now + "',121)", connection);
cmd.CommandTimeout = 0;
rdr = cmd.ExecuteReader();

while (rdr.Read())
{
//MessageBox.Show(rdr[1].ToString(), "rdr 111111111");
Server = rdr[0].ToString();
Account = rdr[1].ToString();
Password = rdr[2].ToString();
int TaskType = Convert.ToInt32(rdr[5]);
if (TaskType == 10000)
{
// timer logout start
}
else if (TaskType == 2222)
TaskType = 2;
else if (TaskType == 3333)
TaskType = 3;
else if (TaskType == 4444)
TaskType = 4;
else if (TaskType == 5555)
TaskType = 5;
else
TaskType = 1;

if (TaskType != 10000)
upg_db(Server, Account, Password, TaskType);
else
logout(Server, Account, Password, TaskType);


}
if (rdr != null)
rdr.Close();
}
catch (Exception ex) { MessageBox.Show(ex.Message, "22ww"); }

finally
{
if (rdr != null)
rdr.Close();
if (connection != null)
connection.Close();
}


}
}
و دو تا تابع استفاده شده در داخل این تابع :

public void logout(string server, string account, string password, int TaskType)
{
DateTime T = DateTime.Now;
int TimeLogouted = rnd.Next(60, 100);// dagige
int TimeLoginAgain = TimeLogouted + rnd.Next(360, 600);//dagige

SqlConnection connection = new SqlConnection(Assist.connectionString);

SqlDataReader rdr = null;
String query = "";
int cookieid = 0;
try
{
connection.Open();
query = "select * from LoginParameters where server='" + server + "' and account='" + account + "'";
SqlCommand cmd2 = new SqlCommand(query, connection);
cmd2.CommandTimeout = 0;
rdr = cmd2.ExecuteReader();
while (rdr.Read())
{
cookieid = Convert.ToInt32(rdr[8].ToString());
Cookies[cookieid] = new CookieContainer();
break;
}
if (rdr != null)
{
rdr.Close();
}

query = "DELETE FROM UpgradeQueue where server='" + server + "' and account='" + account + "'";
SqlCommand command = new SqlCommand(query, connection);
command.ExecuteNonQuery();


query = "INSERT INTO UpgradeQueue (server,account,password,datecreated,dateend,taski d) VALUES(@server,@account, @password,@datecreated,@dateend,@taskid)";
command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
command.Parameters.Add("@server", server);
command.Parameters.Add("@account", account);
command.Parameters.Add("@password", password);
command.Parameters.Add("@datecreated", T);
command.Parameters.Add("@dateend", T.AddMinutes(TimeLogouted));
command.Parameters.Add("@taskid", 1); // main
command.ExecuteNonQuery();


query = "INSERT INTO UpgradeQueue (server,account,password,datecreated,dateend,taski d) VALUES(@server,@account, @password,@datecreated,@dateend,@taskid)";
command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
command.Parameters.Add("@server", server);
command.Parameters.Add("@account", account);
command.Parameters.Add("@password", password);
command.Parameters.Add("@datecreated", T);
command.Parameters.Add("@dateend", T.AddMinutes(TimeLogouted).AddSeconds(rnd.Next(300 , 400)));
command.Parameters.Add("@taskid", 2222); // traintroop
command.ExecuteNonQuery();



query = "INSERT INTO UpgradeQueue (server,account,password,datecreated,dateend,taski d) VALUES(@server,@account, @password,@datecreated,@dateend,@taskid)";
command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
command.Parameters.Add("@server", server);
command.Parameters.Add("@account", account);
command.Parameters.Add("@password", password);
command.Parameters.Add("@datecreated", T);
command.Parameters.Add("@dateend", T.AddMinutes(TimeLogouted).AddSeconds(rnd.Next(180 0, 3600)));
command.Parameters.Add("@taskid", 3333); // seninf
command.ExecuteNonQuery();


query = "INSERT INTO UpgradeQueue (server,account,password,datecreated,dateend,taski d) VALUES(@server,@account, @password,@datecreated,@dateend,@taskid)";
command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
command.Parameters.Add("@server", server);
command.Parameters.Add("@account", account);
command.Parameters.Add("@password", password);
command.Parameters.Add("@datecreated", T);
command.Parameters.Add("@dateend", T.AddMinutes(TimeLogouted).AddSeconds(rnd.Next(200 , 300)));
command.Parameters.Add("@taskid", 4444); // start_advanture
command.ExecuteNonQuery();


query = "INSERT INTO UpgradeQueue (server,account,password,datecreated,dateend,taski d) VALUES(@server,@account, @password,@datecreated,@dateend,@taskid)";
command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
command.Parameters.Add("@server", server);
command.Parameters.Add("@account", account);
command.Parameters.Add("@password", password);
command.Parameters.Add("@datecreated", T);
command.Parameters.Add("@dateend", T.AddMinutes(TimeLogouted).AddSeconds(rnd.Next(200 0, 3600)));
command.Parameters.Add("@taskid", 5555); // gardesh
command.ExecuteNonQuery();

query = "INSERT INTO UpgradeQueue (server,account,password,datecreated,dateend,taski d) VALUES(@server,@account, @password,@datecreated,@dateend,@taskid)";
command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
command.Parameters.Add("@server", server);
command.Parameters.Add("@account", account);
command.Parameters.Add("@password", password);
command.Parameters.Add("@datecreated", T);
command.Parameters.Add("@dateend", T.AddMinutes(TimeLoginAgain));
command.Parameters.Add("@taskid", 10000); // timerlogout
command.ExecuteNonQuery();

}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\r\n\r\n" + account, "db 2" + cookieid);
}
finally { if (connection != null) connection.Close(); }
}
و
public void upg_db(string server, string account, string password, int TaskType)
{

SqlConnection connection = new SqlConnection(Assist.connectionString);

SqlDataReader rdr = null;
String query = "", ip = "", port = "", screen = "", useragent = "", sector = "", tribe = "", activateCode = "";
int serverId = 0, cookieid = -1, tokenlogin = -1;
try
{
connection.Open();
query = "select * from LoginParameters where server='" + server + "' and account='" + account + "' and tokenLogin='0'";
SqlCommand cmd2 = new SqlCommand(query, connection);
cmd2.CommandTimeout = 0;
rdr = cmd2.ExecuteReader();
while (rdr.Read())
{
ip = rdr[2].ToString();
port = rdr[3].ToString();
screen = rdr[4].ToString();
useragent = rdr[5].ToString();
sector = rdr[6].ToString();
tribe = rdr[7].ToString();
cookieid = Convert.ToInt32(rdr[8].ToString());
activateCode = rdr[9].ToString();
serverId = Convert.ToInt32(rdr[10].ToString());
tokenlogin = Convert.ToInt32(rdr[11].ToString());
break;
}
if (rdr != null)
rdr.Close();

if (ip != "" & tokenlogin == 0)
{
query = "UPDATE LoginParameters SET tokenLogin='1' WHERE server='" + server + "' AND account='" + account + "'";
SqlCommand command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
command.ExecuteNonQuery();
if (connection != null)
connection.Close();

Thread t = new Thread((ThreadStart)(() =>
{
mng_acc_database mng = new mng_acc_database(server, account, password, ip, int.Parse(port), useragent, screen, int.Parse(tribe), sector, cookieid, rich_banned, rich_logs, TaskType, activateCode, serverId);
}));
t.IsBackground = true;
t.Start();
}

}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\r\n\r\n" + account, "db 2" + cookieid);
}
finally
{
if (rdr != null)
rdr.Close();
if (connection != null)
connection.Close();
}
}
در داخل این تابع هم یک تابع دیگه دارم که با ترد اونو اجرا کردم که داخلش تابع مربوط به دیتابیس این هست:
public void AddTaskToDatabase(int secends)
{
DateTime T = DateTime.Now;

SqlConnection connection = new SqlConnection(Assist.connectionString);

String query = "";
SqlCommand command;

try
{
connection.Open();
if (secends >= 0)
{
int i = 0;
try
{
query = "select count(*) from UpgradeQueue WHERE server='" + Server + "' AND account='" + Account + "' and taskid<'1000'";
command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
i = Convert.ToInt32(command.ExecuteScalar());
}
catch (Exception ex) { MessageBox.Show(ex.Message + "\r\n" + Account + "\r\n" + Task + "\r\n" + Server, "a000"); }
if (i == 1)// update
{
query = "UPDATE UpgradeQueue SET datecreated='" + T + "', dateend='" + T.AddSeconds(secends) + "', taskid='" + Task + "' WHERE server='" + Server + "' AND account='" + Account + "' and taskid<'1000' and dateend <= convert(datetime,'" + DateTime.Now + "',121)";
command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
command.ExecuteNonQuery();
}
else// insert
{

}
}
else if (secends == -2)// banned
{
query = "DELETE FROM UpgradeQueue WHERE server='" + Server + "' AND account='" + Account + "'";
command = new SqlCommand(query, connection);
command.CommandTimeout = 0;
command.ExecuteNonQuery();
}
else
MessageBox.Show("error secends up\r\n\r\n acc:" + Account, "sec:" + secends + " task:" + Task);

}
catch (Exception ex) { MessageBox.Show(ex.Message, "in thread tsk " + secends); }
finally { if (connection != null) connection.Close(); }
}

وقتی تعداد رکورد های دیتابیس زیاد شد کار به مشکل بر میخوره . مثلا تا زمانی که کمتر از 7 هزار تا هست به خوبی کار میکنه اما 7 هزار تا رو که رد کرد زمان اجرای query ها افزایش پیدا میکنه و کاری که من نوشتم تو یک زمان معین انجام بده رو حدودا 1 ساعت دیرتر انجام میده

Mahmoud.Afrad
جمعه 25 فروردین 1396, 15:05 عصر
میونید کانکشنی که ابتدا ساختید رو بین متدها پاس بدید و کانکشن جدیدی نیاز نیست بسازید.
به جای دیتاریدر، دسته ای از رکوردها را در دیتاتیبل دریافت و پردازش کنید(صفحه بندی داده ها)

در مورد کدهاتون، کاری که این کدها انجام میدن چیه؟ به نظرم خیلی سختش کردی. اگر میتونی یک نمونه پروژه بزار تا بشه روش نظر داد.

sajadf7
جمعه 25 فروردین 1396, 17:42 عصر
میونید کانکشنی که ابتدا ساختید رو بین متدها پاس بدید و کانکشن جدیدی نیاز نیست بسازید.
به جای دیتاریدر، دسته ای از رکوردها را در دیتاتیبل دریافت و پردازش کنید(صفحه بندی داده ها)

در مورد کدهاتون، کاری که این کدها انجام میدن چیه؟ به نظرم خیلی سختش کردی. اگر میتونی یک نمونه پروژه بزار تا بشه روش نظر داد.

یک کانکشن گلوبال میساختم و همه جا از اون استفاده میکردم اما تو اون حالت خیلی زودتر sql server هنگ میکرد.

شما این مدلی فرض کنید که من میخام برای 100،000 تا سایت دو الی 10 تا request ارسال کنم . دور اول که ارسال شد برای یک سایت ، یک زمان رندم بین مثلا 5 الی 30 دقیقه انتخاب بشه و بعد از اون زمان دوباره ارسال درخواست به سایت مورد نظر شرو بشه و ...

زمان ارسال این درخواست ها برای سایت ها نباید یکی باشه . یعنی برای هر سایت یک زمان رندم جدا باید انتخاب بشه.

وقتی وقفه ایجاد کردن برای ارسال هر دور برای یک سایت رو با thread.sleep انجام میدم مصرف رم سیستم بشدت بالا میره و... ( مجبورم تو هر 100000 تا ترد thread.sleep استفادخ کنم که پدر رم رو در میاره )

میام از دیتابیس استفاده میکنم. برای هر سایت در دور اول که درخواست ارسال شد بجای thread.sleep اون زمان وقفه رو در دیتابیس ذخیره میکنم . بعد یک تابع دارم که هر 15 ثانیه دیتابیس رو چک میکنه که هر رکوردی زمانش رسیده بود شروع کنه برای ارسال و ... و دوباره کارش که تموم شد یک زمان رندم دیگه انتخاب میکنه و تو دیتابیس ذخیره میکنه.

فقط مشکل اینجاست که نمیتونم برنامه بزارم

hamid_hr
جمعه 25 فروردین 1396, 18:37 عصر
ببینین شما وقتی یک بار درخواست فرستادید و به صورت رندم در دیتابیس ذخیره کردید
یک ترد ایجاد بیاید یک کوئری بگیرید و بر اساس اون زمانی که ذخیره شده مرتب کنید و این خروجی رو از بالا بخونه بیاد اولی رو بخونه و به میلی ثانیه تبدیل و یک thread.sleep براش بزارید و وقتی از خالت sleep خارج شد یک ترد ایجاد و یک کوئری بگیرید اونایی که زمانش فرا رسیده رو تو جریان بندازید و در ترد اول هم دوباره همون روال را اجرا کنید
اینطوری فک کنم بار ترافیکی دیتابیس خیلی کمتر بشه

sajadf7
شنبه 26 فروردین 1396, 01:27 صبح
ببینین شما وقتی یک بار درخواست فرستادید و به صورت رندم در دیتابیس ذخیره کردید
یک ترد ایجاد بیاید یک کوئری بگیرید و بر اساس اون زمانی که ذخیره شده مرتب کنید و این خروجی رو از بالا بخونه بیاد اولی رو بخونه و به میلی ثانیه تبدیل و یک thread.sleep براش بزارید و وقتی از خالت sleep خارج شد یک ترد ایجاد و یک کوئری بگیرید اونایی که زمانش فرا رسیده رو تو جریان بندازید و در ترد اول هم دوباره همون روال را اجرا کنید
اینطوری فک کنم بار ترافیکی دیتابیس خیلی کمتر بشه

تقریبا میشه گفت این کد هایی که گزاشتم همون کار رو میکنند دیگه.
تو query من فقط اونایی رو میاره که زمانشون رسیده. هر کدوم که زمانشون رسیده اگر به خط 40 ام قطعه کد اول همین پست نگاه کنید دونه دونه براشون یک تابع رو صدا میزنه ( همه تابع هارو در بالا گزاشتم ) به این صورت :

if (TaskType != 10000)
upg_db(Server, Account, Password, TaskType);
else
logout(Server, Account, Password, TaskType);

بعد داخل اون تابع که میره دو سه تا query دیگه اجرا میشه و نهایتا قسمت زمانبر رو با ترد جدا انجام میده

اما نمیدونم قطعه کد من مشکل داره که با زیاد شدن تعداد رکورد ها برنامه کاراییش میاد پایین یا کلا sql server با کار کرد همزمان چند هزار query کلا مشکل داره