اشتراکها
بررسی Native AOT در داتنت 8
Deep .NET - Ahead of Time Compilation (Native AOT) with Eric Erhardt
Scott Hanselman is joined by Eric Erhardt to go deep on all things Native AOT, that is right, Ahead of Time Compilation. Learn about everything Native AOT from start to finish and how .NET leverages this technology to make your apps and code super fast.
Chapters:
00:00:00 Intro
00:04:17 Understanding the Options and Restrictions of Publishing in .NET Apps
00:06:46 Limitations and Benefits of Native AOT
00:12:33 Development and Implementation of Web API AOT
00:16:28 Use of Create Small and Source Generators in Web Development
00:22:03 Role and Impact of Source Generators in Software Development
00:29:17 Application Performance Optimization and Role-Based Optimization in Web Development
00:33:27 Program Optimization Techniques and Trade-offs
00:37:28 Trade-offs and Considerations in Application Optimization
00:41:27 Understanding the Challenges and Limitations of Implementing AOT
00:46:34 Understanding and Implementing AOT
00:52:56 Understanding Model Streaming Extensions
00:55:50 C# 11 and AOT
01:03:49 Understanding and Addressing AOT Compatibility Issues
01:08:54 Understanding Trimming
01:10:35 Understanding and Addressing System Memory Data and Error Handling
01:16:16 Binary Data Compatibility and Source Generation in Visual Studio
01:24:25 Advanced Features
01:25:29 Wrap-up
اشتراکها
کتابخانه AspNetCoreRateLimit
AspNetCoreRateLimit is an ASP.NET Core rate limiting solution designed to control the rate of requests that clients can make to a Web API or MVC app based on IP address or client ID. The AspNetCoreRateLimit package contains an IpRateLimitMiddleware and a ClientRateLimitMiddleware, with each middleware you can set multiple limits for different scenarios like allowing an IP or Client to make a maximum number of calls in a time interval like per second, 15 minutes, etc. You can define these limits to address all requests made to an API or you can scope the limits to each API URL or HTTP verb and path.
همانطور که مطلع هستید سرویس پک سه SQL Server چند روزی است که منتشر شده. این به روز رسانی بر روی یک سرور بدون مشکل نصب شد؛ در سرور دیگر به علت داشتن یک سری برنامه امنیتی مزاحم (که مثلا دسترسی به رجیستری را مونیتور و سد میکنند) با شکست مواجه و در آخر پیغام Fail نمایش داده شد. مجددا آنرا اجرا کردم، سریع تمام مراحل را تمام کرد باز هم Fail را نمایش داد.
خوب؛ گفتم احتمالا مشکلی نیست. سعی کردم به سرور وصل شوم ... پیغام «این سرور دسترسی از راه دور را نمیپذیرد» و از این حرفهای متداول ظاهر شد. به لاگ موجود در Event log ویندوز که مراجعه کردم پیغام خطای زیر نمایان بود:
Script level upgrade for database 'master' failed because upgrade step 'sqlagent100_msdb_upgrade.sql' encountered error 5597, state 1, severity 16. This is a serious error condition which might interfere with regular operation and the database will be taken offline. If the error happened during upgrade of the 'master' database, it will prevent the entire SQL Server instance from starting. Examine the previous errorlog entries for errors, take the appropriate corrective actions and re-start the database so that the script upgrade steps run to completion.
اوه! اوه! اوه! در این لحظهی عرفانی، دیتابیس master نابود شده! نمیشود وصل شد. سروری که داشت تا مدتی قبل بدون هیچ مشکلی کار میکرد، الان دیگر حتی نمیشود به آن وصل شد. به کنسول سرویسهای ویندوز مراجعه کردم (services.msc)، سعی کردم سرویس اس کیوال را که از کار افتاده دستی اجرا کنم، پیغام زیر مجددا در event log ظاهر شد:
FILESTREAM feature could not be initialized. The Windows Administrator must enable FILESTREAM on the instance using Configuration Manager before enabling through sp_configure.
قابلیت FILESTREAM را نمیتواند آغاز کند. پس از مدتی جستجو مشخص شد که این مورد را میشود در رجیستری ویندوز غیرفعال کرد؛ به صورت زیر:
1) Open up Registry Editor
2) Go To HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.MSSQLServer\MSSQLSERVER\FileStream
3) Edit the value "EnableLevel" and set it to 0
4) Restart SQL Server.
2) Go To HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.MSSQLServer\MSSQLSERVER\FileStream
3) Edit the value "EnableLevel" and set it to 0
4) Restart SQL Server.
پس از انجام اینکار، سرویس اس کیوال استارت شد (از طریق کنسول سرویسهای ویندوز). در ادامه، امکان اتصال به آن نبود (حتی با اکانت sa):
Login failed for user 'sa'. Reason: Server is in script upgrade mode. Only administrator can connect at this time. (Microsoft SQL Server, Error: 18401)
باز هم پس از مدتی جستجو معلوم گردید که «کمی باید صبر کرد». آن پیغام اول کار مبتنی بر تخریب دیتابیس master هم بیمورد است. پس از fail شدن نصب سرویس پک، هنوز برنامه نصاب آن در پشت صحنه مشغول به کار است. این مورد به وضوح در task manager ویندوز مشخص است. سرور به مدت 15 دقیقه به حال خود رها شد. پس از آن بدون مشکل اتصال برقرار گردید و همه چیز مجددا شروع به کار کرد.
بنابراین اگر در حین نصب سرویس پک SQL Server مشکلی پیش آمد، نگران نباشید. باید به نصاب آن زمان داد (برنامه mscorsw.exe در پشت صحنه مشغول به کار است). برنامه نصاب آن هم هیچ نوع خطای مفهومی را گزارش نمیدهد. تمام مراحل، بجای نمایش در برنامه تمام صفحه نصاب آن، در event log ویندوز ثبت میشود. این برنامه تمام صفحه فقط کارش نمایش یک progress bar است!
اگر ... هیچکدام از این موارد جواب نداد، امکان بازسازی دیتابیس master نیز وجود دارد: [^ , ^]
ولی دست نگه دارید و سریع اقدام نکنید. ابتدا به task manager مراجعه کنید. آیا برنامه mscorsw.exe در حال اجرا است؟ اگر بله، یعنی هنوز کار نصب تمام نشده. حداقل یک ربع باید صبر کنید.
اشتراکها
شروع کار با تکنولوژی های وب
If you're interested in being a Web Developer but you’re not sure where to start, we have just the course for you. In today’s fast-changing world of technology, navigating the languages, frameworks, platforms, and even the vocabulary can seem confusing. Clear up the confusion with popular experts Michael Choi of Coding Dojo and Christopher Harrison of Microsoft, as they walk you through the basic concepts of web development.
در قسمت قبل به صورت اجمالی با الگوریتمهای داده کاوی در SSDT آشنا شدید. در این قسمت به الگوریتم Naive Bayes خواهیم پرداخت.
برای روشنتر شدن مطلب، سیستم رای گیری را در نظر بگیرید، در رابطه با سیستم رای گیری از طریق این الگوریتم میتوان به پرسشهای زیر پاسخ داد:
- مهمترین آرای هر حزب چه هستند؟
- توزیع آرا در رابطه با یک عمل خاص (پرداخت یارانه یا عدم پرداخت آن) چگونه بوده است؟
- توزیع آرای یک عمل خاص درمیان آرای اعمال دیگر چگونه بوده است و چه ارتباطی بین آنها است؟
این الگوریتم، ارتباط بین ویژگیها را مشخص میکند، این درحالی است که از طریق الگوریتمهای دیگر این کار به سادگی قابل کشف نیست.
یک راه خوب برای شروع داده کاوی ساخت مدل Naïve Bayes و چک کردن ورودی و خروجی برروی تمام ستونها است. مدل حاصل سبب میشود که درک بهتری از دادهها پیدا کرده و ساخت مدلهای دیگر داده کاوی مانند درخت تصمیم و ... راحتتر انجام پذیرد. به همین جهت، اولین الگوریتم معرفی شده نیز این الگوریتم میباشد.
بنابراین زمانیکه با یک مجموعه داده جدید روبرو میشویم، راحتترین راه برای شروع داده کاوی، ساخت یک مدل از Naïve Bayes است، به طوریکه تمامی ستونهای غیرکلید را به عنوان predict یا همان هم ورودی-هم خروجی در نظر میگیریم. پس از آموزش مدل به قسمت Dependency Network میرویم. نمونه ای از شبکه وابستگیها را در شکل زیر مشاهده میکنید که در حقیقت گرافی از نودها است.
نودهای مختلف نشان دهنده ستونهای انتخاب شده هستند و جهت ارتباط بین نودها از ورودی به سمت خروجی است. ارتباطهای دوطرفه نشان دهنده این هستند که از هر یک از دو نود میتوان دیگری را پیش بینی کرد. سمت چپ این گراف در SSDT یک نوار وجود دارد (که در شکل زیر آمده است)، هرچه نوار کناری را به سمت پایین ببریم ارتباطهای قویتر نشان داده شده و ارتباط هایی که دارای قدرت کمتری هستند حذف میشوند. بنابراین زمانی که نوار کناری را در پایینترین حالت قرار دهیم میتوان قویترین ارتباط بین ستونهای ورودی و خروجی را مشاهده نمود.
نکته مهم: اگر هدف ما پیش بینی یک ویژگی باشد، ارتباط قوی ما بین دو ورودی، مشخص میکند که استفاده از هردوی آنها برای پیش بینی یک ویژگی خروجی، کاری بس اشتباه است؛ زیرا ورودیهای شبیه به هم میتوانند اثر دوبرابری داشته باشند. برای مثال در شکل بالا در صورتی که ارتباط موجود بین دو ویژگی Young Frankenstein و Monty Python and the Holy Grail قوی باشد بایستی از انتخاب هر دوی این ویژگیها به عنوان ورودی برای پیش بینی ویژگی Princess Bride پرهیز نمود.
جهت درک بهتر دادهها میتوان به قسمت Attribute Profile مراجعه نمود. همانطور که درشکل زیر آمده است در این بخش ماتریسی از نحوه ارتباط بین تمامی حالات ورودیها و خروجیها نشان داده شده است.
از لیست کشویی، خروجی مدنظر را انتخاب میکنیم و ماتریس درصد پیش بینی خروجی از روی ورودی یا ورودیها نشان داده میشود.
اگر هدف درک شباهتها و اختلافات حالتهای هدف پیش بینی باشد میتوان از دو قسمت Attribute Characteristics و Attribute Discrimination استفاده نمود. در رابطه با Attribute Characteristics دو مساله را باید در نظر داشت:
- قدرت پیش بینی ندارد یعنی نباید در این قسمت از روی ویژگیها به پیش بینی هدفی پرداخت.
- ورودی هایی که امتیازشان از مینیمم امتیاز یک گره پایینتر است نشان داده نمیشوند.
و اما در رابطه با Attribute Discrimination نیز باید قبل از هر قضاوتی، مراقب سطح پشتیبانی (support level) ویژگیها باشیم. برای مثال در رابطه با رای گیری در رابطه با یک عمل خاص مشاهده میشود که اختلاف زیادی بین حزب دموکرات و حزب مستقل وجود دارد که متاسفانه این تفسیر اشتباه است چرا که پس از بررسی مجموعه داده به این نتیجه میرسیم که داده مربوط به حزب مستقل فقط دو مورد است و هردوی آنها در این آمار آمدهاند. یعنی 100 درصد آنها و این درحالی است که داده مربوط به حزب دموکرات زیاد بوده و ممکن است این درصد اعلام شده روی این عمل خاص حتی از حزب مستقل پایینتر باشد. شکل زیر نمایی از Attribute Discrimination می باشد.
از آنجاکه فاز پردازش این الگوریتم فقط اولین دسته مرتب شده از ارتباط بین ورودی و خروجیها را حساب میکند، پس نگرانی از بابت پردازش نیست. بنابراین این الگوریتم برای مجموعه دادههای خیلی بزرگ با ویژگیهای بسیار زیاد، مناسب است.
در این الگوریتم ورودی و خروجی باید Discrete (گسسته) باشند و در صورتیکه Continuous (پیوسته) باشند بایستی Discretize شوند. البته باید درنظر داشت که در حالت کلی این الگوریتم در رابطه با دادههای Continuous کاربرد مناسبی ندارد. بنابراین پیش بینی این دادهها حتی اگر Discretize شوند با این الگوریتم خوب نیست.
در پایان بهتر است دوباره به این نکته اشاره شود که بایستی مراقب بود تا ورودیها تقریبا مستقل از یکدیگر انتخاب شوند؛ زیرا ورودیهای شبیه به هم میتوانند اثر دوبرابری و مخربی داشته باشند که بایستی از آن اجتناب کرد. به دلیل چنین رفتاری، ارزیابی مدل توسط lift chart حتما پیشنهاد میشود.
در این مطلب تعدادی از شایعترین مشکلات حین کار با Entity framework که نهایتا به تولید برنامههایی کند منجر میشوند، بررسی خواهند شد.
مدل مورد بررسی
کوئریهایی که در ادامه بررسی خواهند شد، بر روی رابطهی one-to-many فوق تعریف شدهاند؛ یک کاربر به همراه تعدادی مطلب منتشر شده.
مشکل 1: بارگذاری تعداد زیادی ردیف
در بسیاری از اوقات، در برنامههای خود تنها نیاز به مشاهدهی قسمت خاصی از یک سری از اطلاعات، وجود دارند. به همین جهت بکارگیری متد ToList بدون محدود سازی تعداد ردیفهای بازگشت داده شده، سبب بالا رفتن مصرف حافظهی سرور و همچنین بالا رفتن میزان دادهای که هر بار باید بین سرور و کلاینت منتقل شوند، خواهد شد. یک چنین برنامههایی بسیار مستعد به استثناهایی از نوع out of memory هستند.
راه حل: با استفاده از Skip و Take، مباحث صفحهی بندی را اعمال کنید.
مشکل 2: بازگرداندن تعداد زیادی ستون
فرض کنید View برنامه، در حال نمایش عناوین مطالب ارسالی است. کوئری فوق، علاوه بر عناوین، شامل تمام خواص تعریف شدهی دیگر نیز هست. یک چنین کوئریهایی نیز هربار سبب هدر رفتن منابع سرور میشوند.
راه حل: اگر تنها نیاز به خاصیت Content است، از Select و سپس ToList استفاده کنید؛ البته به همراه نکته 1.
مشکل 3: گزارشگیریهایی که بیشباهت به حملهی به دیتابیس نیستند
فرض کنید قرار است رکوردهای مطالب را نمایش دهید. در حین نمایش این مطالب، در قسمتی از آن باید نام نویسنده نیز درج شود. با توجه به رابطهی تعریف شده، نوشتن post.User.Name به ازای هر مطلب، بسیار ساده به نظر میرسد و بدون مشکل هم کار میکند. اما ... اگر خروجی SQL این گزارش را مشاهده کنیم، به ازای هر ردیف نمایش داده شده، یکبار رفت و برگشت به بانک اطلاعاتی، جهت دریافت نام نویسنده یک مطلب وجود دارد.
این مورد به lazy loading مشهور است و در مواردی که قرار است با یک مطلب و یک نویسنده کار شود، شاید اهمیتی نداشته باشد. اما در حین نمایش لیستی از اطلاعات، بیشباهت به یک حملهی شدید به بانک اطلاعاتی نیست.
راه حل: در گزارشگیریها اگر نیاز به نمایش اطلاعات روابط یک موجودیت وجود دارد، از متد Include استفاده کنید تا Lazy loading لغو شود.
مشکل 4: فعال بودن بیجهت مباحث ردیابی اطلاعات
در اینجا ما فقط قصد داریم که لیستی از اطلاعات را دریافت و سپس نمایش دهیم. در این بین، هدف، ویرایش یا حذف اطلاعات این لیست نیست. یک چنین کوئریهایی مساوی هستند با تشکیل dynamic proxies مخصوص EF جهت ردیابی تغییرات اطلاعات (مباحث AOP توکار). EF توسط این dynamic proxies، محصور کنندههایی را برای تک تک آیتمهای بازگشت داده شده از لیست تهیه میکند. در این حالت اگر خاصیتی را تغییر دهید، ابتدا وارد این محصور کننده (غشاء نامرئی) میشود، در سیستم ردیابی EF ذخیره شده و سپس به شیء اصلی اعمال میگردد. به عبارتی شیء در حال استفاده، هر چند به ظاهر post.User است اما در واقعیت یک User دارای روکشی نامرئی از جنس dynamic proxyهای EF است. تهیه این روکشها، هزینهبر هستند؛ چه از لحاظ میزان مصرف حافظه و چه از نظر سرعت کار.
راه حل: در گزاشگیریها، dynamic proxies را توسط متد AsNoTracking غیرفعال کنید:
مشکل 5: باز کردن تعداد اتصالات زیاد به بانک اطلاعاتی در طول یک درخواست
هر Context دارای اتصال منحصربفرد خود به بانک اطلاعاتی است. اگر در طول یک درخواست، بیش از یک Context مورد استفاده قرار گیرد، بدیهی است به همین تعداد اتصال باز شده به بانک اطلاعاتی، خواهیم داشت. نتیجهی آن فشار بیشتر بر بانک اطلاعاتی و همچنین کاهش سرعت برنامه است؛ از این لحاظ که اتصالات TCP برقرار شده، هزینهی بالایی را به همراه دارند.
روش تشخیص:
داشتن متدهایی که در آنها کار وهله سازی و dispose زمینهی EF انجام میشود (متدهایی که در آنها new Context وجود دارد).
راه حل: برای حل این مساله باید از روشهای تزریق وابستگیها استفاده کرد. یک Context وهله سازی شدهی در طول عمر یک درخواست، باید بین وهلههای مختلف اشیایی که نیاز به Context دارند، زنده نگه داشته شده و به اشتراک گذاشته شود.
مشکل 6: فرق است بین IList و IEnumerable
خروجی کوئری LINQ نوشته شده از نوع IEnumerable است. در EF، هربار مراجعهی مجدد به یک کوئری که خروجی IEnumerable دارد، مساوی است با ارزیابی مجدد آن کوئری. به عبارتی، یکبار دیگر این کوئری بر روی بانک اطلاعاتی اجرا خواهد شد و رفت و برگشت مجددی صورت میگیرد.
زمانیکه در حال تهیهی گزارشی هستید، ابزارهای گزارشگیر ممکن است چندین بار از نتیجهی کوئری شما در حین تهیهی گزارش استفاده کنند. بنابراین برخلاف تصور، data binding انجام شده، تنها یکبار سبب اجرای این کوئری نمیشود؛ بسته به ساز و کار درونی گزارشگیر، چندین بار ممکن است این کوئری فراخوانی شود.
راه حل: یک ToList را به انتهای این کوئری اضافه کنید. به این ترتیب از نتیجهی کوئری، بجای اصل کوئری استفاده خواهد شد و در این حالت تنها یکبار رفت و برگشت به بانک اطلاعاتی را شاهد خواهید بود.
مشکل 7: فرق است بین IQueryable و IEnumerable
خروجی IEnumerable، یعنی این عبارت را محاسبه کن. خروجی IQueryable یعنی این عبارت را درنظر داشته باش. اگر نیاز است نتایج کوئریها با هم ترکیب شوند، مثلا بر اساس رابط کاربری برنامه، کاربر بتواند شرطهای مختلف را با هم ترکیب کند، باید از ترکیب IQueryableها استفاده کرد تا سبب رفت و برگشت اضافی به بانک اطلاعاتی نشویم.
مشکل 8: استفاده از کوئریهای Like دار
این نوع کوئریها که در نهایت به Like در SQL ترجمه میشوند، سبب full table scan خواهند شد که کارآیی بسیار پایینی دارند. در این نوع موارد توصیه شدهاست که از روشهای full text search استفاده کنید.
مشکل 9: استفاده از Count بجای Any
اگر نیاز است بررسی کنید مجموعهای دارای مقداری است یا خیر، از Count>0 استفاده نکنید. کارآیی Any و کوئری SQL ایی که تولید میکند، به مراتب بیشتر و بهینهتر است از Count>0.
مشکل 10: سرعت insert پایین است
ردیابی تغییرات را خاموش کرده و از متد جدید AddRange استفاده کنید. همچنین افزونههایی برای Bulk insert نیز موجود هستند.
مشکل 11: شروع برنامه کند است
میتوان تمام مباحث نگاشتهای پویای کلاسهای برنامه به جداول و روابط بانک اطلاعاتی را به صورت کامپایل شده در برنامه ذخیره کرد. این مورد سبب بالا رفتن سرعت شروع برنامه خصوصا در حالتیکه تعداد جداول بالا است میشود.
مدل مورد بررسی
public class User { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<BlogPost> BlogPosts { get; set; } } public class BlogPost { public int Id { get; set; } public string Title { get; set; } public string Content { get; set; } [ForeignKey("UserId")] public virtual User User { get; set; } public int UserId { get; set; } }
مشکل 1: بارگذاری تعداد زیادی ردیف
var data = context.BlogPosts.ToList();
راه حل: با استفاده از Skip و Take، مباحث صفحهی بندی را اعمال کنید.
مشکل 2: بازگرداندن تعداد زیادی ستون
var data = context.BlogPosts.ToList();
راه حل: اگر تنها نیاز به خاصیت Content است، از Select و سپس ToList استفاده کنید؛ البته به همراه نکته 1.
var list = context.BlogPosts.Select(x => x.Content).Skip(15).Take(15).ToList();
مشکل 3: گزارشگیریهایی که بیشباهت به حملهی به دیتابیس نیستند
foreach (var post in context.BlogPosts) { Console.WriteLine(post.User.Name); }
این مورد به lazy loading مشهور است و در مواردی که قرار است با یک مطلب و یک نویسنده کار شود، شاید اهمیتی نداشته باشد. اما در حین نمایش لیستی از اطلاعات، بیشباهت به یک حملهی شدید به بانک اطلاعاتی نیست.
راه حل: در گزارشگیریها اگر نیاز به نمایش اطلاعات روابط یک موجودیت وجود دارد، از متد Include استفاده کنید تا Lazy loading لغو شود.
foreach (var post in context.BlogPosts.Include(x=>x.User))
مشکل 4: فعال بودن بیجهت مباحث ردیابی اطلاعات
var data = context.BlogPosts.ToList();
راه حل: در گزاشگیریها، dynamic proxies را توسط متد AsNoTracking غیرفعال کنید:
var data = context.BlogPosts.AsNoTracking().Skip(15).Take(15).ToList();
مشکل 5: باز کردن تعداد اتصالات زیاد به بانک اطلاعاتی در طول یک درخواست
هر Context دارای اتصال منحصربفرد خود به بانک اطلاعاتی است. اگر در طول یک درخواست، بیش از یک Context مورد استفاده قرار گیرد، بدیهی است به همین تعداد اتصال باز شده به بانک اطلاعاتی، خواهیم داشت. نتیجهی آن فشار بیشتر بر بانک اطلاعاتی و همچنین کاهش سرعت برنامه است؛ از این لحاظ که اتصالات TCP برقرار شده، هزینهی بالایی را به همراه دارند.
روش تشخیص:
private void problem5MoreThan1ConnectionPerRequest() { using (var context = new MyContext()) { var count = context.BlogPosts.ToList(); } }
راه حل: برای حل این مساله باید از روشهای تزریق وابستگیها استفاده کرد. یک Context وهله سازی شدهی در طول عمر یک درخواست، باید بین وهلههای مختلف اشیایی که نیاز به Context دارند، زنده نگه داشته شده و به اشتراک گذاشته شود.
مشکل 6: فرق است بین IList و IEnumerable
DataContext = from user in context.Users where user.Id>10 select user;
زمانیکه در حال تهیهی گزارشی هستید، ابزارهای گزارشگیر ممکن است چندین بار از نتیجهی کوئری شما در حین تهیهی گزارش استفاده کنند. بنابراین برخلاف تصور، data binding انجام شده، تنها یکبار سبب اجرای این کوئری نمیشود؛ بسته به ساز و کار درونی گزارشگیر، چندین بار ممکن است این کوئری فراخوانی شود.
راه حل: یک ToList را به انتهای این کوئری اضافه کنید. به این ترتیب از نتیجهی کوئری، بجای اصل کوئری استفاده خواهد شد و در این حالت تنها یکبار رفت و برگشت به بانک اطلاعاتی را شاهد خواهید بود.
مشکل 7: فرق است بین IQueryable و IEnumerable
خروجی IEnumerable، یعنی این عبارت را محاسبه کن. خروجی IQueryable یعنی این عبارت را درنظر داشته باش. اگر نیاز است نتایج کوئریها با هم ترکیب شوند، مثلا بر اساس رابط کاربری برنامه، کاربر بتواند شرطهای مختلف را با هم ترکیب کند، باید از ترکیب IQueryableها استفاده کرد تا سبب رفت و برگشت اضافی به بانک اطلاعاتی نشویم.
مشکل 8: استفاده از کوئریهای Like دار
var list = context.BlogPosts.Where(x => x.Content.Contains("test"))
مشکل 9: استفاده از Count بجای Any
اگر نیاز است بررسی کنید مجموعهای دارای مقداری است یا خیر، از Count>0 استفاده نکنید. کارآیی Any و کوئری SQL ایی که تولید میکند، به مراتب بیشتر و بهینهتر است از Count>0.
مشکل 10: سرعت insert پایین است
ردیابی تغییرات را خاموش کرده و از متد جدید AddRange استفاده کنید. همچنین افزونههایی برای Bulk insert نیز موجود هستند.
مشکل 11: شروع برنامه کند است
میتوان تمام مباحث نگاشتهای پویای کلاسهای برنامه به جداول و روابط بانک اطلاعاتی را به صورت کامپایل شده در برنامه ذخیره کرد. این مورد سبب بالا رفتن سرعت شروع برنامه خصوصا در حالتیکه تعداد جداول بالا است میشود.
برنامههای قدیمی، الزاما خیلی قدیمی هم نیستند؛ برنامههایی هستند پر از کوئریهای ذیل:
ویژگی مهم این نوع کوئریها که با جمع زدن رشتهها و یا مقدار دهی مستقیم فیلدها تشکیل شدهاند، «غیر پارامتری» بودن آنها است.
این نوع مشکلات با بکار گیری ORMها به نحو قابل توجهی کاهش یافتهاست؛ زیرا این نوع واسطها در اغلب موارد، در آخر کار کوئریهایی پارامتری را تولید میکنند.
مشکل کوئریهای غیر پارامتری چیست؟
استفادهی وسیع از کوئریهای غیرپارامتری با SQL Server، مشکلی را پدید میآورد به نام «Cache bloat» یا «کش پُف کرده» و این «پُف» به این معنا است که کش کوئریهای اجرا شدهی بر روی SQL Server بیش از اندازه با Query planهای مختلف حاصل از بررسی نحوهی اجرای بهینهی آنها پر شدهاست. هر کوئری که به SQL Server میرسد، جهت اجرای بهینه، ابتدا پردازش میشود و دستور العملی خاص آن، تهیه و سپس در حافظه کش میشود. وجود این کش به این خاطر است که SQL Server هربار به ازای هر کوئری رسیده، این عملیات پردازشی را تکرار نکند. مشکل از زمانی شروع میشود که SQL Server کوئریهایی را که از نظر یک برنامه نویس مانند هم هستند را به علت عدم استفادهی از پارامترها، یکسان تشخیص نداده و برای هر کدام یک Plan جداگانه را محاسبه و کش میکند. این مساله با حجم بالای کوئریهای رسیده دو مشکل را ایجاد میکند:
الف) مصرف حافظهی بالای SQL Server که گاهی اوقات این حافظهی اختصاص داده شدهی به کش کوئریها به بالای یک گیگابایت نیز میرسد.
ب) CPU Usage بالای سیستم
سیستم قدیمی است؛ امکان تغییر کدها را نداریم.
بدیهی است بهترین راه حلی که در اینجا وجود دارد، پارامتری ارسال کردن کوئریها به SQL Server است تا به ازای هر تغییری در مقادیر آنها، این کوئریها باز هم یکسان به نظر برسند و SQL Server سعی در محاسبهی مجدد Plan آنها نکند. اما ... اگر این امکان را ندارید، خود SQL Server یک چنین قابلیتهایی را به صورت توکار تدارک دیدهاست که باید فعال شوند.
فعال سازی پارامتری کردن خودکار کوئریها در SQL Server
اگر نمیتوانید کدهای یک سیستم قدیمی را تغییر دهید، SQL Server میتواند به صورت خودکار اینکار را برای شما انجام دهد. در این حالت فقط کافی است یکی از دو دستور ذیل را اجرا کنید:
حالت simple بیشتر جهت پارامتری کردن خودکار کوئریهای select بکار میرود. اگر میخواهید تمام کوئریهای select, insert, update و delete را نیز پارامتری کنید، باید از حالت forced استفاده نمائید.
فعال سازی بهبود کارآیی SQL Server با کوئریهای Ad-Hoc زیاد
به کوئریهای غیرپارامتری، کوئریهای Ad-Hoc نیز گفته میشود. اگر سیستم فعلی شما، تعداد زیادی کوئری Ad-Hoc تولید میکند، میتوان فشار کاری SQL Server را برای این مورد خاص، تنظیم و بهینه سازی کرد.
فعال سازی گزینهی ویژهی «Optimize for Ad hoc Workloads» سبب میشود تا SQL Server پس از مدتی به صورت خودکار کش Plan کوئریهایی را که به ندرت استفاده میشوند، حذف کند. همین مساله سبب آزاد شدن حافظه و بهبود کارآیی کلی سیستم میگردد. همچنین باید درنظر داشت که کش Plan کوئریها نامحدود نیست و سقفی دارد. به همین جهت آزاد شدن آن، کش کردن کوئریهایی را که بیشتر استفاده میشوند، سادهتر میکند.
برای اعمال آن به یک بانک اطلاعاتی خاص، نیاز است دستورات ذیل را اجرا کرد:
برای مطالعهی بیشتر
Fixing Cache Bloat Problems With Guide Plans and Forced Parameterization
Optimizing ad-hoc workloads
Optimizing for Ad hoc Workloads
SELECT * FROM table1 WHERE OrderDate ='12 Mar 2004' SET @SQL = 'SELECT * FROM table2 WHERE OrderDate = ' + '''' + @Var + '''' EXEC (@SQL)
این نوع مشکلات با بکار گیری ORMها به نحو قابل توجهی کاهش یافتهاست؛ زیرا این نوع واسطها در اغلب موارد، در آخر کار کوئریهایی پارامتری را تولید میکنند.
مشکل کوئریهای غیر پارامتری چیست؟
استفادهی وسیع از کوئریهای غیرپارامتری با SQL Server، مشکلی را پدید میآورد به نام «Cache bloat» یا «کش پُف کرده» و این «پُف» به این معنا است که کش کوئریهای اجرا شدهی بر روی SQL Server بیش از اندازه با Query planهای مختلف حاصل از بررسی نحوهی اجرای بهینهی آنها پر شدهاست. هر کوئری که به SQL Server میرسد، جهت اجرای بهینه، ابتدا پردازش میشود و دستور العملی خاص آن، تهیه و سپس در حافظه کش میشود. وجود این کش به این خاطر است که SQL Server هربار به ازای هر کوئری رسیده، این عملیات پردازشی را تکرار نکند. مشکل از زمانی شروع میشود که SQL Server کوئریهایی را که از نظر یک برنامه نویس مانند هم هستند را به علت عدم استفادهی از پارامترها، یکسان تشخیص نداده و برای هر کدام یک Plan جداگانه را محاسبه و کش میکند. این مساله با حجم بالای کوئریهای رسیده دو مشکل را ایجاد میکند:
الف) مصرف حافظهی بالای SQL Server که گاهی اوقات این حافظهی اختصاص داده شدهی به کش کوئریها به بالای یک گیگابایت نیز میرسد.
ب) CPU Usage بالای سیستم
سیستم قدیمی است؛ امکان تغییر کدها را نداریم.
بدیهی است بهترین راه حلی که در اینجا وجود دارد، پارامتری ارسال کردن کوئریها به SQL Server است تا به ازای هر تغییری در مقادیر آنها، این کوئریها باز هم یکسان به نظر برسند و SQL Server سعی در محاسبهی مجدد Plan آنها نکند. اما ... اگر این امکان را ندارید، خود SQL Server یک چنین قابلیتهایی را به صورت توکار تدارک دیدهاست که باید فعال شوند.
فعال سازی پارامتری کردن خودکار کوئریها در SQL Server
اگر نمیتوانید کدهای یک سیستم قدیمی را تغییر دهید، SQL Server میتواند به صورت خودکار اینکار را برای شما انجام دهد. در این حالت فقط کافی است یکی از دو دستور ذیل را اجرا کنید:
--Forced ALTER DATABASE dbName SET PARAMETERIZATION FORCED --Simple ALTER DATABASE dbName SET PARAMETERIZATION SIMPLE
فعال سازی بهبود کارآیی SQL Server با کوئریهای Ad-Hoc زیاد
به کوئریهای غیرپارامتری، کوئریهای Ad-Hoc نیز گفته میشود. اگر سیستم فعلی شما، تعداد زیادی کوئری Ad-Hoc تولید میکند، میتوان فشار کاری SQL Server را برای این مورد خاص، تنظیم و بهینه سازی کرد.
فعال سازی گزینهی ویژهی «Optimize for Ad hoc Workloads» سبب میشود تا SQL Server پس از مدتی به صورت خودکار کش Plan کوئریهایی را که به ندرت استفاده میشوند، حذف کند. همین مساله سبب آزاد شدن حافظه و بهبود کارآیی کلی سیستم میگردد. همچنین باید درنظر داشت که کش Plan کوئریها نامحدود نیست و سقفی دارد. به همین جهت آزاد شدن آن، کش کردن کوئریهایی را که بیشتر استفاده میشوند، سادهتر میکند.
برای اعمال آن به یک بانک اطلاعاتی خاص، نیاز است دستورات ذیل را اجرا کرد:
use dbName; -- Optimizing for Ad hoc Workloads exec sp_configure 'show advanced options',1; RECONFIGURE; go exec sp_configure 'optimize for ad hoc workloads',1; RECONFIGURE; Go
برای مطالعهی بیشتر
Fixing Cache Bloat Problems With Guide Plans and Forced Parameterization
Optimizing ad-hoc workloads
Optimizing for Ad hoc Workloads