PDA

View Full Version : مشکل در سلکت از تیبل با تعداد رکورد میلیونی



ozzy_mra
یک شنبه 05 دی 1389, 08:43 صبح
سلام
دوستان عزیز من یه تیبل دارم که 3/5 میلیون رکورد داره، وقتی که ازش سلکت میزنم exception تایم اوت میده و اطلاعات رو نمایش نمی ده ، من می خوام کل اطلاعات رو تو دیتا ست بریزم و یه سری کار روش انجام بدم، ولی به خاطر اینکه تایم اوت می ده نمی تونم تو دیتا ست بریزمش، چطور می تونم این مشکل رو حل کنم؟
متشکرم

saman6488
یک شنبه 05 دی 1389, 09:16 صبح
به نظر من دلیل تایم اوت دادن حجم بالای دادهای شماست، که کامل نمیتونه تو حافظه لود بشه، عملیات رو تقسیم کن به چند بخش

Reza_Yarahmadi
یک شنبه 05 دی 1389, 09:19 صبح
ريختن 3 ميليون ركورد توي ديتاست چندان روش مناسبي نيست چون حجم زيادي از رم رو اشغال ميكنه (براي يك ديتابيس معمولي حدود 500مگ)، شما سعي كنيد هر عملياتي كه ميخوايد روي داده ها انجام بديد توي ديتابيس اونو انجام بديد تاهم داده كمتري خونده بشه، هم سرعت پردازش (بدليل استفاده از ايندكسها و ...) بالا بره. در صورت امكان توضيح بديد كه چه كاري ميخوايد روي داده ها انجام بديد تا شايد بشه دستور مناسبي براي اين كار نوشت.
ولي اگر اصرار بر استفاده از روش خودتون داريد ميتونيد در كانكشن استرينك مقدار Connect Timeout رو بيشتر كنيد (فرضا 60)

ozzy_mra
یک شنبه 05 دی 1389, 10:49 صبح
ريختن 3 ميليون ركورد توي ديتاست چندان روش مناسبي نيست چون حجم زيادي از رم رو اشغال ميكنه (براي يك ديتابيس معمولي حدود 500مگ)، شما سعي كنيد هر عملياتي كه ميخوايد روي داده ها انجام بديد توي ديتابيس اونو انجام بديد تاهم داده كمتري خونده بشه، هم سرعت پردازش (بدليل استفاده از ايندكسها و ...) بالا بره. در صورت امكان توضيح بديد كه چه كاري ميخوايد روي داده ها انجام بديد تا شايد بشه دستور مناسبي براي اين كار نوشت.
ولي اگر اصرار بر استفاده از روش خودتون داريد ميتونيد در كانكشن استرينك مقدار Connect Timeout رو بيشتر كنيد (فرضا 60)

کاری که می خوام انجام بدم کانورت اطلاعات از sql به فرمت dbf هست که باید توسط application انجام بشه.
کلاً برای جداولی که تعداد رکورد بالا دارند روش کار اصولی چیه؟ شما فرض کنید که من از همچین تیبلی می خوام گزارش بگیرم که عملیات خیلی سنگینی هم روی داده ها انجام میده در بهترین حالت اگر این کار توسط sp بهینه در سرور انجام بشه و بر روی تمام فیلد هایی که روی آنها عملیات انجام میشه ایندکس مناسب هم گذاشته شده باشه باز هم به علت حجم بالای اطلاعات تایم اوت رخ میده ، شما می فرمائید که تنها راه برای مواجهه با این مشکل افزایش مقدار connect tineOut در کانکشن استرینگه؟

Reza_Yarahmadi
یک شنبه 05 دی 1389, 11:52 صبح
تا جايي كه ميدونم پلاگينهايي براي اين مدل كارها براي SQL Server وجود داره يك مقدار گوگل كنيد ببينيد چيزي پيدا ميكنيد يا نه.
راههاي ديگه اي هم وجود داره مثل اينكه اطلاعات رو تيكه تيكه بخونيد و توي برنامه هر بار تيكه جديد رو به اطلاعات قبلي اضافه كنيد.

تنها راه برای مواجهه با این مشکل افزایش مقدار connect tineOut در کانکشن استرینگه؟مسلما تنها راه نيست و راههاي ديگه اي هم وجود ، ولي در حد سواد و اطلاعات بنده نيست.

ramin_ramin
یک شنبه 05 دی 1389, 15:15 عصر
با سلام
اولا باید حتما ایندکس بندی کرده باشی و در صورت امکان روی فیلد عددی باشه
دوما شما میخواهید چه کاری روی این 5 میلیون رکورد بکنی که یکدفعه میخواهی این کار رو انجام بدی
عزیز من بدون که این کارت هر چی که هست داراری از بدترین راهش میری که اونو انجام بدی

ozzy_mra
دوشنبه 06 دی 1389, 07:38 صبح
با سلام
اولا باید حتما ایندکس بندی کرده باشی و در صورت امکان روی فیلد عددی باشه
دوما شما میخواهید چه کاری روی این 5 میلیون رکورد بکنی که یکدفعه میخواهی این کار رو انجام بدی
عزیز من بدون که این کارت هر چی که هست داراری از بدترین راهش میری که اونو انجام بدی

سلام
البته که این کار ها رو انجام دادم
به هر حال یک سری از کارها هست که شما ناگزیر هستی روی تمام اطلاعات کار کنی ، مثلاً می خوای تکراری ها رو بدست بیاری یا مثل کار من کانورت روی اطلاعات از یه فرمت سطح بالا به یه فایل سطح پایین .
منم می دونم که کارم اصولی نیست و واسه همین هم سوال پرسیدم که اساتید روش درست رو به من یاد بدند

L u k e
دوشنبه 06 دی 1389, 09:58 صبح
فکر کنم CommandTimeOut کارت رو راه بندازه باید 0 ش کنی
از خصوصیات SqlCommand ه

ASKaffash
دوشنبه 06 دی 1389, 13:09 عصر
سلام
فرض کنید یک کلید به نام Pk وجود دارد در یک حلقه هر بار مثلا 1000 رکورد را Fetch کنید
Select Top 1000 * From t Where Pk Between @Pk>@x
در اینجا @x آخرین Pk در Select قبل از این Select است

mehdin69
سه شنبه 07 دی 1389, 20:04 عصر
سلام
دوست من فقط جهت اطلاع مي گم اگه به درستي برنامه رو زمان بندي كني مشكلي نخواهي داشت.
حالا اگه نمي توني اين كار رو به درستي انجام بدي برو إز كامپوننتهاي شركت تلريك استفاده كن كه بدون هيچگونه وقت تلف كردني اطلاعات رو بهت نمايش ميده

Rejnev
سه شنبه 07 دی 1389, 20:48 عصر
از چند نخی استفاده کن که ترد اصلی برنامه (اینترفیست) هنگ نکنه. میتونی روند اجرای کار رو هم نمایش بدی.
برای اجرای دستورات هم نمیدونم چه کدی نوشتی (DataAdapter.Fill نباشه خواهشا) ولی میتونی با استفاده از Datareader رکورد ها رو تک تک و با نهایت سرعت بدون محدودیت زمانی و ... بخونی و پردازش کنی و بری رکورد بعدی (حلقه).
منظورم از پردازش اینه که اونها رو مستقیم بریز توی دیتابیس جدیدت یا مثلا هر چند هزار تا رکوردی که میخونی رو موقت توی یک لیست ذخیره کن و بعد بفرست توی بانک جدید. اینطوری برنامه با حداقل حافظه هم کار خواهد کرد. هر موقع هم که خواستی میتونی عملیات رو متوقف کنی. اگه نمونه کد خواستی بگو تایپ کنم برات

ozzy_mra
چهارشنبه 08 دی 1389, 08:12 صبح
از چند نخی استفاده کن که ترد اصلی برنامه (اینترفیست) هنگ نکنه. میتونی روند اجرای کار رو هم نمایش بدی.
برای اجرای دستورات هم نمیدونم چه کدی نوشتی (DataAdapter.Fill نباشه خواهشا) ولی میتونی با استفاده از Datareader رکورد ها رو تک تک و با نهایت سرعت بدون محدودیت زمانی و ... بخونی و پردازش کنی و بری رکورد بعدی (حلقه).
منظورم از پردازش اینه که اونها رو مستقیم بریز توی دیتابیس جدیدت یا مثلا هر چند هزار تا رکوردی که میخونی رو موقت توی یک لیست ذخیره کن و بعد بفرست توی بانک جدید. اینطوری برنامه با حداقل حافظه هم کار خواهد کرد. هر موقع هم که خواستی میتونی عملیات رو متوقف کنی. اگه نمونه کد خواستی بگو تایپ کنم برات

اتفاقاً با dataadapter.fill پر کردم :لبخند:
متشکرم. ولی یکی از دوستان فرمودند که اگه Connect TimeOut رو زیاد کنم مشکل حل میشه من مقدارشو رو 500 تنظیم کردم:متعجب: ولی باز هم time out error داد
یه سوال دیگه. من کلاً تو پروژه هام از dataadapter.fill استفاده می کنم. مشکلش چیه؟ و اینکه دیگه این سبک رو فراموش کنم و با datareader استفاده کنم؟
من به این خاطر از دیتا ادبتر استفاده می کردم که با هاش دیتا ستو fill می کردم و بع به راحتی روی عناصر و مقادیر دیتا ست کار می کردم. با دیتا ریدر میشه این کار رو انجام داد یعنی یه دیتا ستو فیل کرد ؟

Rejnev
چهارشنبه 08 دی 1389, 14:38 عصر
با datareader روش يكم فرق ميكنه. اگه بخواي خوب از آب در بياد بايد يكم كد نويسي كني.
fill براي ركوردهاي كم (ده ها هزار) گزينه مناسب و راحتيه(توي كد نويسي).
اين يك نمونه برنامه (http://www.eggheadcafe.com/articles/20030205.asp) نوشته شده با همين روشه.اگه برات پيچيده بود بگو يك مثال ساده برات بنويسم.(اگه بهم گفتي بنويس، قبلش يكم مطالعه در مورد جنريك و ساخت كلاس و ... انجام بده.)با تشكر

ozzy_mra
شنبه 11 دی 1389, 08:38 صبح
با datareader روش يكم فرق ميكنه. اگه بخواي خوب از آب در بياد بايد يكم كد نويسي كني.
fill براي ركوردهاي كم (ده ها هزار) گزينه مناسب و راحتيه(توي كد نويسي).
اين يك نمونه برنامه (http://www.eggheadcafe.com/articles/20030205.asp) نوشته شده با همين روشه.اگه برات پيچيده بود بگو يك مثال ساده برات بنويسم.(اگه بهم گفتي بنويس، قبلش يكم مطالعه در مورد جنريك و ساخت كلاس و ... انجام بده.)با تشكر

خیلی ممنونم، اگه خودتم مثالی داشتی و زحمتی برات نبود برام بزاری خیلی ممنونت می شم

Rejnev
شنبه 11 دی 1389, 23:48 عصر
فرض كن جدولي با ستونهاي زير و تعداد زيادي ركورد در اون داري كه قراره از طريق كد نويسي به يك پايگاه داده ديگه مثل mysql منتقل كني:
Person
(
id int,
fName nvarchar,lName nvarchar,
phone nvarchar, address nvarchar
)
من نميدونم ديتابيس مقصد چيه و چطوري ميخواي توش بنويسي، براي همين اون قسمت رو به عهده خودت ميزارم(فرض رو بر اين گرفتم كه مقصد هم اس كيو اله)


public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Thread t = new Thread(copy);
t.IsBackground = true;
t.Start();
}
void copy()
{
SqlConnection cnn = new SqlConnection("data source=.;initial catalog=sourceDb;user=sa");
cnn.Open();
SqlCommand cmd = new SqlCommand("select id,fName,lName,phone,Address from person", cnn);
SqlDataReader dr= cmd.ExecuteReader();
//destination:
SqlConnection cnnWrite = new SqlConnection("data source=.;initial catalog=destinationDb;user=sa");
cnnWrite.Open();
SqlCommand cmdWrite = new SqlCommand("insert into person(id,fname,lname,phone,address)valuse(@id,@fn ame,@lname,@phone,@address)", cnnWrite);
//
while (dr.Read())
{
cmdWrite.Parameters.Clear();
cmdWrite.Parameters.AddWithValue("@id", dr.GetInt32(0));
cmdWrite.Parameters.AddWithValue("@fName", dr.GetString(1));
cmdWrite.Parameters.AddWithValue("@lname", dr.GetString(2));
cmdWrite.Parameters.AddWithValue("@phone", dr.GetString(3));
cmdWrite.Parameters.AddWithValue("@address", dr.GetString(4));
cmd.ExecuteNonQuery();
}
}
}

در ضمن اگه از linq to sql استفاده كني نيازي به ساخت كامند و كانكشن و ريدر نخواهد بود فقط مينويسي:


void copyWithLinq()
{
//destination:
SqlConnection cnnWrite = new SqlConnection("data source=.;initial catalog=destinationDb;user=sa");
cnnWrite.Open();
SqlCommand cmdWrite = new SqlCommand("insert into person(id,fname,lname,phone,address)valuse(@id,@fn ame,@lname,@phone,@address)", cnnWrite);
foreach (Person item in personList)
{
cmdWrite.Parameters.Clear();
cmdWrite.Parameters.AddWithValue("@id", item.ID);
cmdWrite.Parameters.AddWithValue("@fName", item.FirstName);
cmdWrite.Parameters.AddWithValue("@lname", item.LastName);
cmdWrite.Parameters.AddWithValue("@phone", item.Phone);
cmdWrite.Parameters.AddWithValue("@address", item.Address);
cmd.ExecuteNonQuery();
}
}

براي اينكه پيشرفت كار رو بتوني توي يك progress bar نمايش بدي بايد اولا تعداد ركوردها رو بدست بياري كه بر اساس اون maxValue پروگرس رو مشخص كني و ثانيا به ازاي هر ركوردي كه ثبت ميشه يكي به اون value اون اضافه كني(دقت كن كه براي تغيير خصوصياتش وقتي توي يك نخ ديگه هستي بايد invoke ش كني)
به نظر خودم اين روش جواب ميده و حافظه خور كمي داره. منظورم اينه كه اگه برنامه در ابتداي اجرا مثلا 20 مگ رم گرفته باشه، در انتها نهايتا شايد به 30 مگ برسه. محدوديتي هم از بابت تايم اوت نبايد داشته باشه.
سعي كن كد رو براي استفاده خودت تغيير بدي و اگه جاييش رو متوجه نشدي بگو.

ozzy_mra
یک شنبه 12 دی 1389, 08:47 صبح
خیلی ازتون ممنونم ، تعداد maxValue رو هم از خود datareader بگیرم دیگه مثل دیتا ست؟

Rejnev
یک شنبه 12 دی 1389, 15:50 عصر
نه. فك نكنم داشته باشه. اگه اينطور بود كه از حلقه while استفاده نميكرديم. يك كوئري معلوم نيست چند تا ركورد برگردونه. علت اينكه dataset ميتونه تعداد بده اينه كه بعد از خوندن و پر شدن معلوم ميشه چند ركورد در اون قرار گرفته.
اگه توي linq باشه كه با تابع Count ميشه. در غير اينصورت فكر ميكنم بايد قبلش يك كوئري اجرا كنيد و تعداد ركوردها رو بدست بياريد:

select count(*) from person