به زبان ساده، وقتی شما متغیر جدیدی را ایجاد میکنید، با توجه به نوع (Type) آن متغیر، "مقدار" متغیر شما در Stack یا Heap قرار خواهد گرفت.
Stack
این ساختمان داده، داخل Memory پیاده سازی شده است و تعدادی از متغیرهایی را که ما داخل کد ایجاد میکنیم، در این نوع ساختمان داده از Memory نگهداری میشوند.
شرط قرار گرفتن مقدار یک متغیر داخل Stack این است که متغیر از نوع Value Type باشد. در زبان #C، بطور کلی Struct و Enumها Value Type هستند و بصورت پیشفرض داخل Stack قرار میگیرند. تمامی ValueTypeها در #C، بطور implicit از System.ValueType ارث بری میکنند.
Typeهای زیر، Value Typeهای پیشفرض تعریف شدهی در زبان #C هستند که به آنها Simple Type نیز گفته میشوند:
Represents | Type |
Boolean value | bool |
8-bit unsigned integer | byte |
16-bit Unicode character | char |
128-bit precise decimal values with 28-29 significant digits | decimal |
64-bit double-precision floating point type | double |
32-bit single-precision floating point type | float |
32-bit signed integer type | int |
64-bit signed integer type | long |
8-bit signed integer type | sbyte |
16-bit signed integer type | short |
32-bit unsigned integer type | uint |
64-bit unsigned integer type | ulong |
16-bit unsigned integer type | ushort |
اگر سورس هرکدام از این تایپها مانند Int32 را در ریپازیتوری CoreFX مایکروسافت بررسی کنید، متوجه خواهید شد که تمامی این تایپها از نوع Struct تعریف شدهاند و همانطور که گفتیم، بطور پیشفرض، Structها داخل Stack قرار خواهند گرفت.
طول عمر متغیرهایی که داخل Stack قرار گرفتهاند، منحصر به پایان اجرای یک متد است. بدین معنا که بعد از به پایان رسیدن یک متد، تمامی متغیرهای مورد استفاده در آن متد، از حافظه Stack بطور خودکار حذف خواهند شد. متغیرهایی که داخل Stack قرار میگیرند، نوع و حجم مقادیرشان بر اساس Type ای دارند، در زمان Compile-Time مشخص است.
public static int Add(int number1, int number2) { // number1 is on the stack (function parameter) // number2 is on the stack (function parameter) int sum = number1 + number2; // sum is on the stack (local variable) return sum; }
در زبان #C و در مرحله Compile-Time، کدها به زبان IL (مخفف Intermediate Language) ترجمه میشوند که با نامهای MSIL (مخفف Microsoft Intermediate Language ) و CIL (مخفف Common Intermediate Language ) نیز، این زبان شناخته میشود. ساختار این زبان Stack-based بوده و با شناخت آن، با مفهوم Stack نیز بهتر میتوانیم آشنا شویم.
IL زبانی است که CLR (مخفف Common Language Runtime) را که همان Runtime مایکروسافت است، شناخته و اجرا میکند. قابل ذکر است که Runtime مایکروسافت Open-Source بوده و سورس آن با نام CoreCLR در گذشته از این آدرس و در حال حاضر با نام Runtime از این آدرس قابل دسترسی است.
C:\Program Files (x86)\Microsoft SDKs\Windows\{version}\Bin\ildasm.exe
.method private hidebysig static int32 Add(int32 number1, int32 number2) cil managed { .locals init (int32 V_0, int32 V_1) IL_0001: ldarg.0 // Stack is: [2] IL_0002: ldarg.1 // Stack is: [2, 5] IL_0003: add // Stack is: [7] IL_0004: stloc.0 // Stack is: [] and V_0's value is: 7 IL_0005: ldloc.0 // Stack is: [7] IL_0006: stloc.1 // Stack is: [] and V_1's value is: 7 IL_0009: ldloc.1 // Stack is: [7] IL_000a: ret // Return [7] }
میتوانید لیست دستورات مورد استفاده در CIL را از اینجا ببینید.
در ادامه، خط به خط، خروجی حاصل را بررسی میکنیم:
2- از کلمه کلیدی ldarg (مخفف Load Argument) برای لود کردن آرگومان یا همان پارامتر ورودی متد، داخل Stack استفاده میشود.
• ldarg.0 به معنای لود کردن پارامتر ورودی اول، داخل Stack است و با فراخوانی آن، Stack Frame دارای یک عضو که مقدار آن 2 است، میشود.
3- با استفاده از کلمه کلیدی add، مقادیر موجود در Stack با یکدیگر جمع میشوند و Stack Frame دارای یک عضو که مقدار آن 7 است، میشود.
4- با استفاده از کلمه کلیدی stloc (مخفف Store Local)، آخرین عضو موجود در Stack، داخل متغیر محلی ذکر شده، قرار گرفته و ذخیره میشود.
5- با استفاده از کلمه کلیدی ldloc (مخفف Load Local)، میتوان متغیر محلی ذخیره شده را داخل Stack قرار داد.
6- در نهایت، مقدار 7، داخل متغیر 1 یا همان V_1 با دستور stloc.1 بار دیگر ذخیره، با ldloc.1 لود شده و با استفاده از دستور ret، برگشت داده میشود.
* نکته: اگر کدها را بطور دقیق بررسی کرده باشید، احتمالا فکر کرده اید که چه نیازی به ایجاد یک متغیر اضافی و ریختن نتیجه داخل آن و سپس برگشت دادن نتیجه، در مرحله 6 است؟!
* نکته: احتمالا تا به اینجا دلیل بوجود آمدن StackOverflowException را متوجه شده باشید. فضای Stack محدود است. این فضا در سیستمهای 32 بیت برابر با 1 مگابایت و در سیستمهای 64 بیت برابر با 4 مگابایت است (Reference). اگر حجم متغیرهایی که روی استک Push میشوند، این محدودیت را رد کنند و یا اگر یک متد بطور دائم خودش را صدا بزند (Recursive) و هیچگاه از آن خارج نشود، با خطای StackOverflowException مواجه میشوید.
Heap
.Heap: a group of things placed, thrown, or lying one on another
در مقابل ساختار ترتیبی و منظم Stack، ساختار Heap قرار دارد. Heap قسمتی از حافظه است که ساختار، ترتیب و Layout خاصی ندارد.
وقتی یک متغیر از نوع string را ایجاد میکنیم، مقدار آن داخل Heap و Memory-Address آن متغیر روی Heap، در Stack نگه داری میشود:
public static void SayHi() { string name = "Moien"; }
در این مثال، چون string یک class است، مقدار آن داخل heap ذخیره شده و آدرس آن قسمت (segment) از memory، روی Stack قرار میگیرد:
.method private hidebysig static void SayHi() cil managed { .locals init (string V_0) IL_0001: ldstr "Moien" // Stack is: [memory-address of string in heap] IL_0006: stloc.0 IL_0007: ret }
به متغیرهایی که مقادیرشان داخل Heap ذخیره میشوند، Reference-Type گفته میشود.
* نکته: در این مثال متغیری به نام name ایجاد شده که از آن هیچ استفادهای نشده است. در زمان JIT-Compilation، با توجه با Optimizationهای موجود در سطح CLR، این متد بطور کلی اضافه تشخیص داده شده و از آن صرفنظر خواهد شد.
Boxing and Unboxing
به فرایند تبدیل یک Value-Type مانند int که بصورت پیشفرض داخل Stack ذخیره میشود، به یک object که در داخل Heap ذخیره میشود، Boxing گفته میشود. انجام این عمل باعث allocation بر روی memory میشود که سربار زیادی دارد.
با انجام عمل Boxing، قادر خواهیم بود تا بعنوان مثال یک عدد را بر خلاف روال عادی آن، روی Heap ذخیره کنیم:
public static void Boxing() { const int number = 5; object boxedNumber = number; // implicit boxing using implicit cast object boxedNumber = (object)number; // explicit boxing using direct cast }
در ابتدا عدد 5 روی Stack ذخیره شده بود، اما با Box کردن آن، یعنی قرار دادن مقدار آن داخل یک object، مقدار از Stack به Heap انتقال داده شده و allocation اتفاق خواهد افتاد:
.method public hidebysig static void Boxing() cil managed { .locals init (object V_0) IL_0001: ldc.i4.5 // Stack is: [5] IL_0002: box [System.Runtime]System.Int32 // Stack is: [memory-address of 5 in heap] IL_0007: stloc.0 IL_0008: ret }
به عکس این عمل، یعنی تبدیل یک Reference-Type به یک Value-Type، اصطلاحا Unboxing گفته میشود:
public static void Unboxing() { object boxedNumber = 5; int number = (int)boxedNumber; }
که نتیجه آن، به این صورت خواهد بود:
.method public hidebysig static void Unboxing() cil managed { .locals init (object V_0, int32 V_1) IL_0001: ldc.i4.5 // Stack is: [5] IL_0002: box [System.Runtime]System.Int32 // Stack is: [memory-address of 5 in heap] IL_0007: stloc.0 // Stack is: [] IL_0008: ldloc.0 // Stack is: [memory-address of 5 in heap] IL_0009: unbox.any [System.Runtime]System.Int32 // Stack is: [5] IL_000e: stloc.1 // Stack is: [] IL_000f: ret }
تلاش تیمهای مایکروسافت طی سالهای اخیر، باعث افزایش Performance فوق العاده در NET Core. و ASP.NET Core شده است. یکی از دلایل این Performance، جلوگیری بسیار زیاد از allocation در کدهای خود NET. است، که این امر به واسطه اولویت قرار دادن استفاده از Structها میسر گردیده است.
برخلاف Stack که طول عمر متغیرهای موجود در آن، در انتهای یک متد پایان مییابند، متغیرهای allocate شدهی در Heap به این شکل نبوده و در صورت حذف نکردن آنها بصورت دستی، تا پایان طول عمر اجرای برنامه داخل memory باقی خواهند ماند. اینجا، جاییست که Garbage Collector در NET. وارد عمل میشود.
interface I { string M1() => "I.M1"; string M2() => "I.M2"; } abstract class A : I {} class C : A { public string M1() => "C.M1"; public virtual string M2() => "C.M2"; } class Program { static void Main() { I obj = new C(); System.Console.WriteLine(obj.M1()); System.Console.WriteLine(obj.M2()); } }
بهبود کارآیی IDEهای Jetbrains
سالها است که IDEهای Jetbrains برای اینکه در سکوهای کاری متفاوت قابل اجرا باشند، با جاوا نوشته میشوند. برای مثال Rider که یک IDE مخصوص دات نت است نیز با جاوا نوشته شدهاست و مابقی آنها نیز به همین صورت. اگر به مسیر C:\Program Files\JetBrains\JetBrains Rider 2018.3.4\bin\rider64.exe.vmoptions مراجعه کنید، فایل با پسوند vmoptions در حقیقت تنظیمات Java Virtual Machine یا JVM را به همراه دارد. این فایل طوری تنظیم شدهاست که کمترین منابع را مصرف کند؛ به همین جهت شاید در حین کار کردن با این IDEها احساس کنید که کند هستند. تنظیمات JVM مخصوص جاوای ویندوز و جاوای مک و لینوکس را در اینجا و اینجا میتوانید مطالعه کنید.
اگر بر این اساس فایل rider64.exe.vmoptions را بخواهیم تکمیل کنیم، میتوان به تنظیمات زیر رسید:
-Xms1024m -Xmx3072m -Xss64m -XX:ReservedCodeCacheSize=512m -XX:+UseCompressedOops -XX:NewRatio=2 -Dfile.encoding=UTF-8 -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=250 -XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=512m -XX:MaxPermSize=1024m -XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:MaxTenuringThreshold=1 -XX:SurvivorRatio=8 -XX:+UseCodeCacheFlushing -XX:+AggressiveOpts -XX:+CMSClassUnloadingEnabled -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=65 -XX:+CMSScavengeBeforeRemark -XX:+UseCMSInitiatingOccupancyOnly -XX:-TraceClassUnloading -XX:+AlwaysPreTouch -XX:+TieredCompilation -XX:+DoEscapeAnalysis -XX:+UnlockExperimentalVMOptions -XX:LargePageSizeInBytes=256m -XX:+DisableExplicitGC -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:+PrintFlagsFinal -XX:+CMSPermGenSweepingEnabled -XX:+UseAdaptiveGCBoundary -XX:+UseSplitVerifier -XX:CompileThreshold=10000 -XX:+OptimizeStringConcat -XX:+UseStringCache -XX:+UseFastAccessorMethods -XX:+UnlockDiagnosticVMOptions -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -Djdk.http.auth.tunneling.disabledSchemes="" -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Xverify:none
پس از این تغییرات اگر Rider را اجرا کنید، حداقل نسبت به قبل دو برابر RAM مصرف خواهد کرد. همچنین بار اولی که برنامه را اجرا میکنید، چون تعدادی از این تنظیمات بر روی نحوهی JIT تاثیرگذار هستند، کمی طول میکشد تا کار کامپایل جدید آن صورت گیرد و از دفعات آتی اجرای آن، بهبود کارآیی را احساس خواهید کرد.
علاوه بر موارد فوق، فایل C:\Program Files\JetBrains\JetBrains Rider 2018.3.4\bin\idea.properties را نیز میتوانید جهت اعمال تغییرات زیر ویرایش کنید:
idea.max.intellisense.filesize=3500 idea.cycle.buffer.size=2048
Performance of your ASP.NET web application is important. There is a lot of evidence to suggest that slow loading times and clunky interaction, will drive customers elsewhere. Even in the case of internal applications where the users have no option but to use the application, their satisfaction is tightly coupled to speed.
There are a ton of ways to improve the performance of a website, let's look at fifteen of them.
با آمدن SQL server 2008 استفاده از کتابخانه SQL-DMO برای انجام یک سری از امور بر روی اس کیوال سرور با استفاده از برنامه نویسی منسوخ شد. یکی از تواناییهای این کتابخانه لیست کردن سرورهای اس کیوال (قابل دسترسی) موجود در شبکه بود.
برای مثال توسط این کتابخانه به صورت زیر میتوان اینکار را انجام داد:
در قطعه کد زیر فرض بر این است که ارجاعی به کتابخانه sqldmo را در برگه com مربوط به project->add reference اضافه کردهاید:
using SQLDMO;
using System.Collections.Generic;
public static List<string> GetSQLServersList2()
{
List<string> result = new List<string>();
ApplicationClass sqlApp = new ApplicationClass();
NameList lst = sqlApp.ListAvailableSQLServers();
for (int i = 1; i <= lst.Count; i++)
result.Add(lst.Item(i));
lst = null;
sqlApp = null;
return result;
}
using System.Collections.Generic;
using System.Data;
using System.Data.Sql;
public class CListServers
{
public static List<string> GetSQLServersList()
{
List<string> result = new List<string>();
// Retrieve the enumerator instance and then the data.
var instance = SqlDataSourceEnumerator.Instance;
var table = instance.GetDataSources();
// Display the contents of the table.
foreach (DataRow row in table.Rows)
{
result.Add(string.Format("{0}\\{1}", row[0], row[1]));
}
return result;
}
}
کتابخانه COM یاد شده (SQL-DMO) در SQL server 2008 با کتابخانه SMO جایگزین شده است.
در این حالت خواهیم داشت:
using System.Collections.Generic;
using System.Data;
using Microsoft.SqlServer.Management.Smo;
public class CListServers
{
public static List<string> GetSQLServersListSMO()
{
List<string> result = new List<string>();
DataTable dt = SmoApplication.EnumAvailableSqlServers(false);
if (dt.Rows.Count > 0)
{
foreach (DataRow dr in dt.Rows)
{
result.Add(dr["Name"].ToString());
}
}
return result;
}
}
SQL Indexing
دلیل استفاده از ایندکس چیست؟
این سوالی است که ممکن است هر توسعه دهندهای به آن در ابتدا پاسخ دهد: «جهت بالابردن سرعت و کارآیی!» حال اگر بپرسیم چگونه؟ توضیحات چندان دقیقی ارائه نمیشود.
ایندکس چیست؟
ایندکس شیءای از دیتابیس است میتواند برروی یک یا چند ستون ایجاد شود (تا 16 ستون). هنگامیکه ایندکسی ایجاد میگردد، ساختار دادهای (BTree) جهت بهینه سازی عملیات مقایسه نیز ایجاد میشود. اس کیو ال سرور بدون داشتن ایندکس، برای دریافت اطلاعات درخواستی مجبور است کل ردیفهای جدول را جستجو نماید. این کار مانند این است که شما بدون اطلاع از شماره صفحه (محل) عنوان درخواستی، به دنبال آن در صفحات یک کتاب باشید. حال اگر به ایندکس (فهرست) کتاب مراجعه کنید به سرعت و حداقل اتلاف وقت میتوانید محل یا شماره صفحهی عنوان مورد نظر را، بدون جستجوی کلیهی صفحات کتاب، پیدا کنید و به آن مراجعه کنید. ایندکس جدول نیز اجازه میدهد بدون جستجوی کلیه رکوردها، رکورد مورد نظر را دریافت نمایید.مثال:
SELECT [computer_id],[nic_device_id],[nic_vendor_id],[nic_desc] FROM [eXpress].[dbo].[nics]
فرض کنید در جدول بالا ایندکس گذاری انجام نشده باشد و قصد داشته باشید رکوردهایی را دریافت نمایید که در آنها computer_id>5100 باشد. اس کیو ال سرور مجبور است کلیه رکوردهای جدول را جهت اعمال شرط بررسی نماید.
حال، برروی ستون computer_id ایندکسی را اعمال مینماییم و شرط computer_id>5100 را مجدد بررسی میکنیم. اس کیو ال از محل رکوردهای با مقادیر بزرگتر از 5100 اطلاع دارد و از جستجوی کل جدول اجتناب میکند. چرا؟ بدلیل اینکه براساس این ستون مرتب شده است.
انواع ایندکس
دو نوع ایندکس اصلی وجود دارد: ایندکس خوشهای و ایندکس غیرخوشهای
ایندکس خوشهای
نحوهی ذخیره سازی فیزیکی رکوردها را تغییر میدهد. هنگامیکه یک ایندکس خوشهای را ایجاد میکنید، بر روی یک ستون (یا ترکیبی از چند ستون)، اس کیو ال سرور رکوردها را براساس ستون/ها بصورت صعودی مرتب شده (مانند یک دیکشنری که کلیه کلمات بصورت الفبایی قرار گرفتهاند) ذخیره مینماید.
بوسیله ایندکس زیر تمام رکوردها براساس ستون computer_id مرتب شده ذخیره میگردند.CREATE CLUSTERED INDEX [IX_CLUSTERED_COMPUTER_ID] ON [dbo].[nics] ([computer_id] ASC)
همانطور که اشاره شد، رکوردها بصورت مرتب شده براساس ستون انتخاب شدهی در
جدول نگهداری میشوند. اما این مرتب سازی توسط ساختار BTree بهشرح زیر انجام
خواهد شد. جدول زیر را در نظر داشته باشید:
فرض کنید بعد ایندکس گذاری ستون StudId جدول فوق، درخت BTree زیر ایجاد میگردد که این ساختار بهصورت جداگانهای بر روی دیسک ذخیره میگردد. در این درخت، مقدار گره سمت چپ ریشه از آن کمتر و مقدار گره سمت راست ریشه از آن بیشتر است (البته عکس این فرض نیز امکان پذیر است).
و سپس کوئریهای زیر را صادر میکنید:
Select * from student where studid = 103; Select * from student where studid = 107;
با ایندکس گذاری، کوئری اول، بعد از اولین عمل مقایسه و کوئری دوم بعد از 3 عمل مقایسه پیدا میشود؛ بهشرح زیر:
- مقایسه 107 با 103 و انتقال به گره سمت راست
- مقایسه 107 با 106 و انتقال به گره سمت راست
- مقایسه 107 با 107 و یافتن مقدار درخواستی و بازگشت رکورد
در صورتیکه تعداد رکوردها کم باشند، تفاوت کارآیی جداول دارای ایندکس و بدون ایندکس قابل لمس نخواهد بود.
ایندکس غیرخوشهای
این نوع ایندکس، تغییری در نحوهی ذخیره سازی رکوردها انجام نمیدهند. ولی شیء دیگری را که شامل ستون/هایی که قرار است ایندکس شوند و اشارهگر به رکورد (RID) هستند، در جدول ایجاد میکند. برای مثالی از ایندکس غیرخوشهای در دنیای واقعی، میتوان به فهرست انتهای کتابها که شامل عناوین و شماره صفحهی مربوطه میباشد، اشاره کرد.
نکته: RID به موقعیت فیزیکی رکورد اشاره خواهد کرد و شامل شناسه، شماره صفحه و تعداد رکوردهای در یک صفحه میباشد.
برای درک بهتر به سناریوی زیر دقت کنید:
کتابی داریم که شامل 1200 صفحه میباشد و فهرست مطالب آن شامل عناوین و
شماره صفحات عناوین میباشد. حال اگر عنوان درخواستی A در صفحات 700، 300،
800 قرار داشته باشد، برای رفتن به این صفحات، مراحل زیر را برای هر یک طی
خواهید کرد:
- یافتن شماره صفحه عنوان درخواستی با مراجعه به فهرست انتهای کتاب.
- در ادامه شما صفحهای را در میانهی کتاب، باز میکنید؛ چون عدد 700 مقداری از نصف 1200 برزگتر است.
- چند صفحه به جلو رفته، شماره صفحه 750 خواهد بود و هنوز به شرط مورد نظر نرسیدهاید.
- پس مجددا چند صفحه به عقب بازگشته تا به صفحهی مورد نظر، 700، برسید.
مراحل فوق برای یافتن عنوان A واقع شدهی در صفحه 700 انجام شد که همین مراحل نیز برای سایر صفحات میتواند انجام شود. در این مثال، صفحه فهرست مطالب کتاب، به ایندکس غیرخوشهای تعبیر خواهد شد.
این نوع ایندکسها جهت ستون هایی مفید هستند که مقادیر آن تکرار خواهد شد؛ مانند جدولی با بیش از چند میلیون رکورد که دارای ستون نوع حساب است، ولی تعداد نوع حساب منحصر بفرد محدودی را خواهد داشت. فرض کنید مقادیر منحصر بفرد، ستون نوع حساب A، B، C باشد. زمانیکه برروی این ستون ایندکس گذاری غیرخوشهای انجام میشود، فهرست ما دارای سه عنوان خواهد بود که هر عنوان به صفحات مربوط به همان عنوان اشاره خواهد کرد. به این ترتیب هنگامیکه برروی نوع حساب عملیات جستجو انجام شود، اس کیو ال میداند رکوردهای نوع حساب مثلا A در کدام صفحات قرار دارد و بهسرعت رکوردهای متناظر را پیدا مینماید.
A: 300, 700, 800 B: 100, 110 C: 600, 1200
ایندکس غیرخوشه ای توسط دستور زیر ایجاد میگردد:
CREATE NONCLUSTERED INDEX [IX_NONCLUSTERED_COMPUTER_ID] ON [dbo].[nics] ([computer_id] ASC)
نکته: یک جدول میتواند بیش از یک ایندکس غیرخوشهای و فقط و
فقط یک ایندکس خوشهای داشته باشد.
ارتباط ایندکس خوشهای و غیر خوشهای
اشارهگر به رکورد (RID) در یک جدول دارای ایندکس خوشهای، کلید ایندکس خوشهای خواهد بود.
مزایا و معایب ایندکس
مزایا:جدولی بدون ایندکس خوشهای، heap table شناخته میشود. یک جدول هیپ، دادهی مرتب شده نخواهد داشت و به منظور دریافت اطلاعات، اس کیو ال سرور مجبور است کل ردیفهای جدول را بررسی نماید که این عملیات Scan نامیده میشود. ولی در صورت استفاده از ایندکس خوشهای برروی یک ستون، اس کیو ال، جهت یافتن اطلاعات مورد جستجو با توجه به BTree عملیات جستجو را از ریشه شروع، از شاخهها عبور کرده و به برگ که همان اطلاعات درخواستی است میرسد که این عملیات Seek نامیده میشود. عملیات Seek طبیعتا از Scan سریعتر است.
ایندکس غیرخوشهای، شامل مجموعهای از ستونها و ارجاعاتی به رکوردها یا کلید ایندکس خوشهای است (ارتباط بین ایندکس غیر خوشهای با خوشهای). بهدلیل حجم کم این نوع ایندکس، میتواند ردیفها یا کلیدهای ایندکس خوشه ای بیشتری در صفحهی ایندکس وجود داشته باشد که باعث افزایش کارآیی I/O میگردد.
معایب:
ایندکس گذاری، در طی عملیات درج، ویرایش و حذف، باعث سربار میگردد. هنگامیکه تغییری بر روی رکوردهای جدول انجام میشود، سبب تغییراتی نیز بر روی ایندکسها میگردد (هنگامیکه برگهای از کتابی جدا شود، نیاز است شماره صفحات و فهرست انتهایی کتاب مجددا بهروز گردد) که این تغییرات باعث ایجاد هزینه میشود. بنابراین خیلی اهمیت دارد که هنگام طراحی ایندکس گذاری به سربارها نیز توجه کنید. بهعنوان مثال هنگامیکه توسط دستور Delete رکوردی را از جدولی حذف نمایید، نیاز است رکوردها مجددا مرتب شوند که این یک سربار است.
ایندکس گذاری ، سرباری بنام bookmark lookup دارد. bookmark lookup فرآیندی جهت یافتن سایر ستونهایی است که در ایندکس گذاری وجود ندارند و براساس RID هستند.
Want to learn about the latest and greatest in the 64-bit Visual Studio 2022? Join Scott Hanselman and Visual Studio product team as they take Visual Studio 2022 for a spin.
20:27 Profiling .NET apps in Visual Studio 2022
23:19 Cross platform apps with WSL and CMake in Visual Studio 2022
26:07 Testing your .NET app on Linux
28:00 Easily create CI/CD pipelines using GitHub actions with Visual Studio 2022
30:40 Balloon drop!
Extended Events/Trace
Extended Events، زیر ساخت مدیریت رخدادها در SQL Server است. برای مثال در نگارش 2016 آن بیشاز 300 رخداد در SQL Server تعریف شدهاند و زمانیکه در مورد اجرای کوئریها بحث میکنیم، این رخدادها بیشتر مدنظر ما هستند:
sql_statement_completed sp_statement_completed rpc_completed sql_batch_completed
علاوه بر اینها، رخدادهای بسط یافتهی زیر را نیز میتوان مورد استفاده قرار داد:
query_post_compilation_showplan query_post_execution_showplan query_pre_execution_showplan
استفاده از Extended Events برای جمع آوری اطلاعات آماری کوئریها
برای آزمایش نحوهی کار با Extended Events، ابتدا رویهی ذخیره شدهی زیر را ایجاد میکنیم:
USE [WideWorldImporters]; GO DROP PROCEDURE IF EXISTS [Application].[usp_GetCountryInfo]; GO CREATE PROCEDURE [Application].[usp_GetCountryInfo] @Country_Name NVARCHAR(60) AS SELECT * FROM [Application].[Countries] [c] JOIN [Application].[StateProvinces] [s] ON [s].[CountryID] = [c].[CountryID] WHERE [c].[CountryName] = @Country_Name; GO
سپس یک سشن Extended Events سفارشی را به صورت زیر ایجاد میکنیم:
/* Create XE session to capture sql_statement_completed and sp_statement_completed */ IF EXISTS ( SELECT * FROM sys.server_event_sessions WHERE [name] = 'QueryPerf') BEGIN DROP EVENT SESSION [QueryPerf] ON SERVER; END GO CREATE EVENT SESSION [QueryPerf] ON SERVER ADD EVENT sqlserver.sp_statement_completed(WHERE ([duration]>(1000))), ADD EVENT sqlserver.sql_statement_completed(WHERE ([duration]>(1000))) ADD TARGET package0.event_file(SET filename=N'C:\Temp\QueryPerf\test.xel',max_file_size=(256)) WITH ( MAX_MEMORY=16384 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS, MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB, MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF); GO
سپس نیاز است تا این سشن را که QueryPerf نام دارد، در قسمت management->extended events، اجرا و آغاز کرد:
در ادامه ابتدا بر روی بانک اطلاعاتی WideWorldImporters، کلیک راست کرده و یک پنجرهی new query جدید را ایجاد میکنیم:
WHILE 1 = 1 BEGIN EXECUTE [Application].[usp_GetCountryInfo] N'United States'; END
سپس مجددا یک پنجرهی new query دیگر را باز میکنیم:
WHILE 1 = 1 BEGIN SELECT [s].[StateProvinceName], [s].[SalesTerritory], [s].[LatestRecordedPopulation], [s].[StateProvinceCode] FROM [Application].[Countries] [c] JOIN [Application].[StateProvinces] [s] ON [s].[CountryID] = [c].[CountryID] WHERE [c].[CountryName] = 'United States'; END
کوئریهای هر دو پنجره را به صورت مجزایی اجرا کنید. سپس در قسمت management->extended events، بر روی سشن QueryPerf کلیک راست کرده و گزینهی View live data را انتخاب کنید:
این زندهترین خروجی یک سشن رخدادهای بسط یافتهاست. کار کردن با آن نسبت به روشی که در قسمت قبل بررسی کردیم، سادهتر و سریعتر است و همچنین گزارش آن به صورت خودکار تولید میشود.
یک نکته: در اینجا در قسمت Details، اگر بر روی هر ردیف کلیک کنید، امکان انتخاب و نمایش آن در لیست بالای صفحه توسط گزینهی Show Column in table وجود دارد.
در آخر در قسمت management->extended events، بر روی سشن QueryPerf کلیک راست کرده و گزینهی Stop Session را انتخاب کنید. اکنون اگر به پوشهی C:\Temp\QueryPerf مراجعه کنید، فایل xel حاوی اطلاعات این گزارش را نیز میتوانید مشاهده نمائید (به ازای هربار اجرای این سشن، یک فایل جدید را تولید میکند).
این فایل توسط Management Studio قابل گشودن و بررسی است و دقیقا همان نمای گزارش live data را به همراه دارد.
کنفرانس مجازی blazor day
The blazor day is the online event around Blazor technologies. Originally, this event was organized by three MVP friends, Adrien, Christophe, and Denis. Their objective of this event is to share their passion for .NET and more particularly Blazor. Joined by the famous Charline to upgrade the event to the next level. Blazor is part of the ASP.NET Core product which is offered in Open Source by Microsoft....