PDA

View Full Version : نحوه ی نوشتن الگوریتم و کدنویسی بهینه



negar.rafie
سه شنبه 29 مرداد 1392, 14:18 عصر
سلام
دوستان خیلی جاها دیدیم و شنیدیم که باید کدها و الگوریتم هامون را بهینه بنویسیم
حالا میخواستم یک مثال بزنید و بگید که چه کد و یا الگوریتمی بهینه است و چه الگوریتمی بهینه نیست
ممنون

amir200h
سه شنبه 29 مرداد 1392, 14:26 عصر
سلام
دوستان خیلی جاها دیدیم و شنیدیم که باید کدها و الگوریتم هامون را بهینه بنویسیم
حالا میخواستم یک مثال بزنید و بگید که چه کد و یا الگوریتمی بهینه است و چه الگوریتمی بهینه نیست
ممنون

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

veniz2008
سه شنبه 29 مرداد 1392, 15:27 عصر
سلام.
برای داشتن یک برنامه بهینه شما نیاز به کدهای بهینه و الگوریتم های بهینه خواهید داشت.
فرض کنید که میخوایم مجموعه ای از رکوردها رو بصورت همزمان درج کنیم. شاید برای این کار دو قطعه کد زیر متصور باشه :

con = new SqlConnection("Data source =(local);initial catalog = testgrid;integrated security = true");
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
SqlCommand cmd = new SqlCommand("insert into student2 values(" + dataGridView1.Rows[i].Cells[0].Value + ",'" + dataGridView1.Rows[i].Cells[1].Value + "',N'" + dataGridView1.Rows[i].Cells[2].Value + "',N'" + dataGridView1.Rows[i].Cells[3].Value + "'", con);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
قطعه کد دوم :

for (int i = 0; i <= t - 1; i++)
{
if(Convert.ToBoolean(dataGridView1.Rows[i].Cells[4].Value) == true)
{

s = s + "insert into student2 values(" + dataGridView1.Rows[i].Cells[0].Value + ",'" + dataGridView1.Rows[i].Cells[1].Value + "',N'" + dataGridView1.Rows[i].Cells[2].Value + "',N'" + dataGridView1.Rows[i].Cells[3].Value + "')" + ";";
}
}

s = s.Remove(s.Length - 1, 1);
con = new SqlConnection("Data source =(local);initial catalog = testgrid;integrated security = true");
con.Open();
SqlCommand cmd = new SqlCommand(s, con);
cmd.ExecuteNonQuery();
con.Close();
هر دوی این دستورات یک کار مشترک رو انجام میدن اما به دو روش متفاوت. اولی به تعداد رکوردهای موجود در گرید عمل اتصال به دیتابیس رو انجام میده و هر بار یک رکورد رو درج میکنه و دوباره ارتباط رو قطع میکنه. ولی دستور دوم درون حلقه همه رکوردها رو جمع میزنه و در خارج از حلقه با یکبار وصل شدن به دیتابیس عمل درج چندین رکورد رو انجام میده. کدامیک از این روش ها سریعتره؟
گول تعداد خط کد کمتر رو نخورید. همیشه تعداد کد کمتر لزوما بهینه تر نیست.
قطعا اونی که یکبار به دیتابیس وصل میشه و عمل درج رو انجام میده سریعتر خواهد بود.
بذارید مثال دوم رو هم بزنم :
فرض کنید بخوایم بفهمیم که آیا یک شماره شناسایی (کلید) که توسط کاربر وارد شده است در جدولی با تعداد رکوردهای خیلی زیاد وجود داره یا نه. برای این کار دو کوئری زیر رو در نظر بگیرید :
1. استفاده از دستور EXISTS :

if(EXISTS(select UserID from TblUser where UserID = @userid))
2. استفاده از count :

select count(UserID) from TblUser where UserID = @userid
کوئری اول (دستور EXISTS ) به محض پیدا کردن رکورد، دیگه جستجو رو ادامه نمیده ولی کوئری دوم (دستور count) تا آخرین رکورد جدول رو پیمایش میکنه. این فقط یک مثال ساده بود.
ضمن اینکه سبک برنامه نویسی هم بسیار موثر خواهد بود. استفاده از sp ها دارای سرعت بیشتری نسبت به روش های کدنویسی مستقیم در محیط ویژوال هست (حداقل در ADO.Net).
رعایت کردن مجموعه ای از این نکات میتونه یک برنامه بهینه رو ایجاد کنه.
من در زیر یکسری موارد رو برای افزایش سرعت عرض میکنم (هم سمت سی شارپ و هم سمت دیتابیس ):
1. کلید جدول رو که معمولا جستجوهای زیادی بر پایه اون انجام میشه، حتی الامکان int در نظر بگیرید. چراکه سرعت در جستجوی فیلدهای عددی نسبت به غیر عددی بیشتر هست.
2. کلید رو تا حد امکان ساده بگیرید و از ابرکلید(کلید ترکیبی) استفاده نکنید.
3. تا حد امکان از nvarchar استفاده نکنید چراکه دو برابر varchar فضای دیتابیس رو اشغال میکنن.
4. تا حد امکان جداول رو به گونه ای بسازید که نیاز به join های بی مورد بین جداول نباشه.
5. به غیر از فیلد کلید که خود sql بصورت اتومات یک clustered index براش میسازه. خودتون با توجه به نیاز پروزتون یک یا چند non clustered index برای جداولتون ایجاد کنید. البته در ایجاد تعداد زیاد این ایندکس ها زیاده روی نکنید. یکی از راه های تشخیص اینکه چه فیلدی رو non clusterd index قرار بدید اینه که روی چه فیلدی بیشتر عملیات جستجو رو انجام می دید. البته معیارهای دیگه ای هم هست که توصیه میکنم حتما درباره ایندکس ها مطالعه بفرمایید. چون ایندکس مناسب بر روی سرعت جستجوها (در تعداد رکوردهای زیاد) قدرت خودش رو به معرض نمایش میزاره.
6. استفاده از کوئری های بهینه (یک مثال رو در بالا نوشتم ).
7. سخت افزار قدرتمند. بدون شک شما برای محاسبه و جابه جایی اطلاعات به cpu و رم مناسب نیاز خواهید داشت.
گذشته از این موارد، طراحی درست و سبک کدنویسی ما میتونه اهمیت زیادی داشته باشه. مثلا استفاده از stored procedure ها در مقایسه با روش های معمولی کارآمدتر خواهد بود.

RIG000
سه شنبه 29 مرداد 1392, 16:32 عصر
سلام.
برای داشتن یک برنامه بهینه شما نیاز به کدهای بهینه و الگوریتم های بهینه خواهید داشت.
فرض کنید که میخوایم مجموعه ای از رکوردها رو بصورت همزمان درج کنیم. شاید برای این کار دو قطعه کد زیر متصور باشه :

con = new SqlConnection("Data source =(local);initial catalog = testgrid;integrated security = true");
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
SqlCommand cmd = new SqlCommand("insert into student2 values(" + dataGridView1.Rows[i].Cells[0].Value + ",'" + dataGridView1.Rows[i].Cells[1].Value + "',N'" + dataGridView1.Rows[i].Cells[2].Value + "',N'" + dataGridView1.Rows[i].Cells[3].Value + "'", con);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
قطعه کد دوم :

for (int i = 0; i <= t - 1; i++)
{
if(Convert.ToBoolean(dataGridView1.Rows[i].Cells[4].Value) == true)
{

s = s + "insert into student2 values(" + dataGridView1.Rows[i].Cells[0].Value + ",'" + dataGridView1.Rows[i].Cells[1].Value + "',N'" + dataGridView1.Rows[i].Cells[2].Value + "',N'" + dataGridView1.Rows[i].Cells[3].Value + "')" + ";";
}
}

s = s.Remove(s.Length - 1, 1);
con = new SqlConnection("Data source =(local);initial catalog = testgrid;integrated security = true");
con.Open();
SqlCommand cmd = new SqlCommand(s, con);
cmd.ExecuteNonQuery();
con.Close();
هر دوی این دستورات یک کار مشترک رو انجام میدن اما به دو روش متفاوت. اولی به تعداد رکوردهای موجود در گرید عمل اتصال به دیتابیس رو انجام میده و هر بار یک رکورد رو درج میکنه و دوباره ارتباط رو قطع میکنه. ولی دستور دوم درون حلقه همه رکوردها رو جمع میزنه و در خارج از حلقه با یکبار وصل شدن به دیتابیس عمل درج چندین رکورد رو انجام میده. کدامیک از این روش ها سریعتره؟
گول تعداد خط کد کمتر رو نخورید. همیشه تعداد کد کمتر لزوما بهینه تر نیست.
قطعا اونی که یکبار به دیتابیس وصل میشه و عمل درج رو انجام میده سریعتر خواهد بود.
بذارید مثال دوم رو هم بزنم :
فرض کنید بخوایم بفهمیم که آیا یک شماره شناسایی (کلید) که توسط کاربر وارد شده است در جدولی با تعداد رکوردهای خیلی زیاد وجود داره یا نه. برای این کار دو کوئری زیر رو در نظر بگیرید :
1. استفاده از دستور EXISTS :

if(EXISTS(select UserID from TblUser where UserID = @userid))
2. استفاده از count :

select count(UserID) from TblUser where UserID = @userid
کوئری اول (دستور EXISTS ) به محض پیدا کردن رکورد، دیگه جستجو رو ادامه نمیده ولی کوئری دوم (دستور count) تا آخرین رکورد جدول رو پیمایش میکنه. این فقط یک مثال ساده بود.
نکته های زیادی وجود داره که باعث میشه سرعت برنامه افزایش پیدا کنه. مثلا بحث مدیریت کردن دیتایتبل و دیتاست که مستقیما از رم سیستم استفاده میکنن هست. خیلی از دوستان این اشیا رو به حال خودشون رها میکنن در حالیکه این رم به سیستم برگشت داده نمیشه (تا زمانیکه برنامه در حال اجرا هست) و خود ما باید بصورت دستی این رم رو آزاد کنیم. توجه نکردن به این مورد میتونه سرعت اجرای برنامه رو کم کنه. تصور کنید در 3 فرم متوالی قصد استفاده از شی دیتایتبل رو برای تعداد رکوردهای زیاد دارید و این دیتاتیبل ها مدیریت نشه. یه سیستم متوسط با رم 1 گیگ مگه چقدر رم خالی داره که تاوان کد نویسی اشتباه برنامه نویس رو بپردازه؟
خیلی از دوستان با dispose سعی در آزاد سازی حافظه دارند که این دستور در ازاد سازی رم سیستم ناتوان هست. برای این کار ما از کلاس GC (Grabber Collector) و از متد Collect اون کمک میگیریم. منظور از dt همون دیتاتیبل ما هست. با کد زیر حدود 90 درصد رم اختصاص داده شده برگشت داده میشه که بسیار موثر خواهد بود. اگر از دوستان کسی هست که کدی داشته باشه که بشه 100% رم تخصیص داده شده به دیتاتیبل رو پس گرفت، ممنون میشم اینجا قرار بده (من هرچی ور رفتم نتونستم چیزی رو پیدا کنم).

dt.Clear();
GC.Collect();

ضمن اینکه سبک برنامه نویسی هم بسیار موثر خواهد بود. استفاده از sp ها دارای سرعت بیشتری نسبت به روش های کدنویسی مستقیم در محیط ویژوال هست (حداقل در ADO.Net).
رعایت کردن مجموعه ای از این نکات میتونه یک برنامه بهینه رو ایجاد کنه.
من در زیر یکسری موارد رو برای افزایش سرعت عرض میکنم (هم سمت سی شارپ و هم سمت دیتابیس ):
1. کلید جدول رو که معمولا جستجوهای زیادی بر پایه اون انجام میشه، حتی الامکان int در نظر بگیرید. چراکه سرعت در جستجوی فیلدهای عددی نسبت به غیر عددی بیشتر هست.
2. کلید رو تا حد امکان ساده بگیرید و از ابرکلید(کلید ترکیبی) استفاده نکنید.
3. تا حد امکان از nvarchar استفاده نکنید چراکه دو برابر varchar فضای دیتابیس رو اشغال میکنن.
4. تا حد امکان جداول رو به گونه ای بسازید که نیاز به join های بی مورد بین جداول نباشه.
5. به غیر از فیلد کلید که خود sql بصورت اتومات یک clustered index براش میسازه. خودتون با توجه به نیاز پروزتون یک یا چند non clustered index برای جداولتون ایجاد کنید. البته در ایجاد تعداد زیاد این ایندکس ها زیاده روی نکنید. یکی از راه های تشخیص اینکه چه فیلدی رو non clusterd index قرار بدید اینه که روی چه فیلدی بیشتر عملیات جستجو رو انجام می دید. البته معیارهای دیگه ای هم هست که توصیه میکنم حتما درباره ایندکس ها مطالعه بفرمایید. چون ایندکس مناسب بر روی سرعت جستجوها (در تعداد رکوردهای زیاد) قدرت خودش رو به معرض نمایش میزاره.
6. استفاده از کوئری های بهینه (یک مثال رو در بالا نوشتم ).
7. سخت افزار قدرتمند. بدون شک شما برای محاسبه و جابه جایی اطلاعات به cpu و رم مناسب نیاز خواهید داشت.
گذشته از این موارد، طراحی درست و سبک کدنویسی ما میتونه اهمیت زیادی داشته باشه. مثلا استفاده از stored procedure ها در مقایسه با روش های معمولی کارآمدتر خواهد بود.
لطفا " در مورد clustered index توضیح بیشتری بدید ... کجا میتونم کتاب مناسبی به فارسی پیدا کنم؟ تو کتاب فروشی های انقلاب کتاب مناسبی از دیتابیس هست ؟
در Grabber Collector ما میتونیم مورد دیتا تیبل استفاده کنیم . دیگه کجا ها میشه استفاده کرد؟ ادرسی هست که بهینه این کلاس رو پیاده سازی کنه؟
در مورد nvarchar و varchr اگه nvarchar انتخاب کنیم مابقی فضای باقی مانده برگردونده میشه... تفاوتش با var char چیه؟!!!

veniz2008
سه شنبه 29 مرداد 1392, 17:23 عصر
لطفا " در مورد clustered index توضیح بیشتری بدید ... کجا میتونم کتاب مناسبی به فارسی پیدا کنم؟ تو کتاب فروشی های انقلاب کتاب مناسبی از دیتابیس هست ؟
متاسفانه کتاب خیلی خوبی من ندیدم. یه کتاب فارسی هست که من مطالعه کردم "شروع کار با sql server" نوشته Robbin Dewson ترجمه عبدالوهاب فخر یاسری. من خیلی خوشم از ترجمش نیومد. فکر میکنم حداقل یک مترجم دیگه هم این کتاب رو ترجمه کرده ولی از کیفیت ترجمه بی اطلاع هستم.
در این کتاب حدود 24 صفحه و در قالب یک فصل مجزا ایندکس ها رو بطور کامل توضیح داده ولی نیاز هست که چندین مرتبه به دقت متن رو مطالعه کنید. در کنار کتاب مذکور، چندین ویدئو زبان اصلی رو هم نگاه کردم. به نظرم تلفیق این دو تا با هم خیلی موثر هست.
اما اینکه cluster index (ایندکس خوشه ای) چی هست به زبان خیلی ساده اینکه sql در زمان تعیین کلید اصلی جدول، بصورت اتوماتیک کلید اصلی رو بعنوان کلاستر ایندکس در نظر میگیره. وجود کلاستر ایندکس باعث میشه ترتیب و سورت فیزیکی رکوردها همیشه حفظ بشه. این یعنی اینکه اگر شما رکوردهای با آی دی مثلا 1 ، 5، 37، 98 ، 110 و 250 رو داشته باشید و الان فرضا آی دی 46 رو درج کنید، این کلاستر ایندکس باعث میشه که رکورد با آی دی 46 بعد از آی دی 37 و قبل از آی دی 98 قرار یگیره. به عبارتی با وجود اینکه این رکورد آخرین رکورد درج شده هست ولی چون ترتیب فیزیکی در کلاستر ایندکس لحاظ میشه باعث میشه رکوردهای جدول جابه جا بشن تا رکورد جدید در جای مناسب خودش (بین 37 و 98 قرار بگیره). این کار باعث میشه که سرعت جستجو در یک جدول مثلا 700 هزار رکوردی بسیار سریع انجام بشه (چراکه رکوردها به ترتیب ذخیره میشن).
نکته : هر جدولی فقط یک کلاستر ایندکس میتونه داشته باشه. به همین خاطر اگر در جدولی نیاز هست غیر از فیلد کلید جستجوهای زیادی رو براساس فیلد غیر کلید هم داشته باشید اینجاست که NonClusterd Index معنا پیدا میکنه. البته این تنها دلیل برای ایجاد یک nonclustered index برای یک فیلد نیست و دلایل دیگه ای هم وجود داره.
بحث ایندکس ها بسیار مهم و متنوع هست و نکات بسیاری در انتخاب ، استفاده و بهینه سازی اونها وجود داره. امکان توضیح دادن کامل اون در اینجا وجود نداره. حتما در این زمینه کتاب مطالعه کنید.


در مورد nvarchar و varchr اگه nvarchar انتخاب کنیم مابقی فضای باقی مانده برگردونده میشه... تفاوتش با var char چیه؟!!!در مورد nvarchar تنها تفاوتی که وجود داره بحث ساپورت کردن از یونیکد (از جمله زبان فارسی) هست وگرنه باقیمانده فضا رو مثل varchar برگشت میده. فقط چون تعداد کاراکترهای بیشتری رو پشتیبانی میکنه به همین خاطر تعداد بایت های بیشتری رو هم برای ذخیره سازی کاراکترها نیاز داره (دو برابر varchar فضا اشغال میکنه).