بررسی مفهوم دیتاست خارجی و درونی
ابتدا در management studio از منوی Query، گزینهی Include actual execution plan را انتخاب میکنیم. سپس کوئریهای زیر را اجرا میکنیم:
USE [WideWorldImporters]; GO SET STATISTICS IO ON; GO /* What's are the inner and outer data sets? */ SELECT [ol].[OrderLineID], [o].[CustomerID] FROM [Sales].[OrderLines] [ol] INNER JOIN [Sales].[Orders] [o] ON [ol].[OrderID] = [o].[OrderID] WHERE [o].[CustomerID] = 185; GO
در اینجا دیتاست خارجی، همان index seek بالایی است که بر روی جدول Orders انجام شدهاست. اولین ردیف بازگشت داده شدهی توسط آن به همراه OrderID مربوطه را به حلقهی تو در توی Inner Join ارسال میکند. سپس index seek دوم بر روی جدول OrderLines، بر اساس OrderID دیتاست خارجی، ردیف مرتبطی را در صورت وجود یافته و به حلقهی تو در توی Inner Join بازگشت میدهد که در نهایت به select ارسال میشود و این عملیات به همین ترتیب ادامه پیدا میکند. این خلاصهی کاری است که یک حلقهی تو در تو انجام میدهد.
سؤال: اگر جای این دیتاستها را عوض کنیم چه اتفاقی رخ خواهد داد؟
در کوئری زیر توسط گزینهی FORCE ORDER سبب شدهایم تا جای دیتاستهای OUTER/INNER تغییر کند (البته این query hint، کاربرد عملی ندارد و صرفا جهت نمایش دیتاستها از آن استفاده کردهایم):
SELECT [ol].[OrderLineID], [o].[CustomerID] FROM [Sales].[OrderLines] [ol] INNER JOIN [Sales].[Orders] [o] ON [ol].[OrderID] = [o].[OrderID] WHERE [o].[CustomerID] = 185 OPTION (FORCE ORDER);
یک نکته: در این تصاویر بجای nested loop، از عملگر Hash Match استفاده شدهاست. اگر بخواهیم بهینه سازی کوئری را وادار کنیم تا از nested loop استفاده کند، میتوان کوئری فوق را توسط یک INNER LOOP JOIN به صورت زیر نوشت:
SELECT [ol].[OrderLineID], [o].[CustomerID] FROM [Sales].[OrderLines] [ol] INNER LOOP JOIN [Sales].[Orders] [o] ON [ol].[OrderID] = [o].[OrderID] WHERE [o].[CustomerID] = 185 OPTION (FORCE ORDER); GO
همانطور که مشاهده میکنید اینبار به علت بالا رفتن تعداد ردیفهایی که باید پردازش کند، به یک پلن بسیار غیر بهینه رسیدهاست که برای بهبود آن مجبور شدهاست Parallelism را نیز فعال کند.
در این حالت اگر هر سه کوئری فوق را با هم اجرا کنیم، تا بتوانیم هزینهی آنها را در کوئری پلن نهایی تولید شده، با یکدیگر مقایسه کنیم، هزینهی کوئری اول صفر درصد، کوئری دوم 1 درصد و کوئری سوم 99 درصد نسبت به کل batch محاسبه میشود. علت آن را نیز در برگهی messages، با مشاهدهی logical reads 477304 مربوط به کوئری سوم میتوان مشاهده کرد که نسبت به سایر کوئریها بسیار بیشتر است. بنابراین بهتر است در کار بهینه ساز کوئریها به صورت دستی دخالت نکنیم!
بهبود کارآیی یک کوئری، با حذف حلقهی تو در توی کوئری پلن آن در حالت Key lookup
کوئری زیر را با فرض انتخاب گزینهی Include actual execution plan در منوی کوئری، اجرا میکنیم:
SELECT [ContactPersonID], [OrderDate], [CustomerPurchaseOrderNumber] FROM [Sales].[Orders] WHERE [ContactPersonID] = 3144;
ایندکسهایی که در این کوئری پلن استفاده شدهاند، شامل موارد پیشفرض زیر هستند؛ یکی بر روی OrderID که کلید اصلی جدول است، تشکیل شده و دیگری بر روی ContactPersonID که در قسمت where کوئری فوق مورد استفاده قرار گرفتهاست:
ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [PK_Sales_Orders] PRIMARY KEY CLUSTERED ( [OrderID] ASC ) GO CREATE NONCLUSTERED INDEX [FK_Sales_Orders_ContactPersonID] ON [Sales].[Orders] ( [ContactPersonID] ASC )
برای بهبود این وضعیت، NONCLUSTERED INDEX تعریف شده را به صورت زیر تغییر میدهیم تا ستونهای OrderDate و CustomerPurchaseOrderNumber را INCLUDE کند:
CREATE NONCLUSTERED INDEX [FK_Sales_Orders_ContactPersonID] ON [Sales].[Orders] ( [ContactPersonID] ASC ) INCLUDE ( [OrderDate], [CustomerPurchaseOrderNumber] ) WITH (DROP_EXISTING = ON) ON [USERDATA]; GO
SELECT [ContactPersonID], [OrderDate], [CustomerPurchaseOrderNumber] FROM [Sales].[Orders] WHERE [ContactPersonID] = 3144;
چون ایندکس جدید تعریف شده کاملا کوئری ما را پوشش میدهد، دیگر نیازی به ایجاد یک nested loop، جهت کار با چندین index متفرقه نیست.
بهبود کارآیی یک کوئری، با حذف حلقهی تو در توی کوئری پلن آن در حالت RID lookup
در اینجا یک جدول کپی را از روی جدول اصلی Orders ایجاد کردهایم؛ به همراه تعریف یک NONCLUSTERED INDEX بر روی ستون ContactPersonID آن:
USE [WideWorldImporters] GO DROP TABLE [Sales].[Copy_Orders] GO SELECT * INTO [Sales].[Copy_Orders] FROM [Sales].[Orders]; GO CREATE NONCLUSTERED INDEX [NCI_Copy_Orders_ContactPersonID] ON [Sales].[Copy_Orders] ( [ContactPersonID] ); GO
SELECT [ContactPersonID], [OrderDate], [CustomerPurchaseOrderNumber] FROM [Sales].[Copy_Orders] WHERE [ContactPersonID] = 3144;
در اینجا یک nested loop را به همراه RID lookup داریم (RID به معنای row id است). همچنین واژهی heap نیز ذکر شدهاست. در این حالت اطلاعات یک چنین جدولی بدون هیچگونه ترتیبی ذخیره شدهاند؛ بنابراین نیاز به شماره ردیف آن (RID) برای برقراری ارتباطات میباشد. Key lookup زمانی رخ میدهند که یک جدول دارای یک clustered index باشد و RID lookup، در حالت عکس آن رخ میدهد. دقیقا مانند جدول کپی ایجاد شده، که دارای یک clustered index نیست.
در صورت مشاهدهی RID lookup نیز میتوانیم ستونهایی از کوئری را که در NONCLUSTERED INDEX ذکر نشدهاند، include کنیم:
CREATE NONCLUSTERED INDEX [NCI_Copy_Orders_ContactPersonID] ON [Sales].[Copy_Orders] ( [ContactPersonID] ASC ) INCLUDE ( [OrderDate], [CustomerPurchaseOrderNumber] ) WITH (DROP_EXISTING = ON) ON [USERDATA]; GO
WebAssembly, or Wasm, is on its way to becoming the next big thing in software development, allowing us to develop more reusable code across programming stacks. It will also enable the deployment of smaller packages more securely. This talk will focus on the view of a .NET developer using WebAssembly in their projects, whether client-side, server-side, or plugins.
Agenda
0:00:00 – Introduction
0:01:44 – Presentation Start
0:04:36 – Wasm on the client
0:08:27 – Wasm on the server
0:11:51 – ASP.NET Core in Wasi
0:21:41 – Wasm in the cloud
0:32:38 – Wasm for plugins
0:36:07 – Wasm plugins samples
0:49:05 – .NET 8 and the future
0:55:08 – Who’s working on this?
1:03:13 – Outro
مقدمه ای بر Bot Framework مایکروسافت
Essentially, a bot is an application that can automate repetitive tasks or serve information to a user and, more and more, can interact with a user using natural language. As these bots get more intelligent and better at understanding us, this is providing a wide spectrum of use cases for bots to be used by and assist almost everyone.
کار یک کامپایلر ترجمه قطعهای از اطلاعات به چیز دیگری است. کامپایلر سیشارپ، machine code معادل دستورات دات نتی را تهیه نمیکند. Machine code، کدی است که مستقیما بر روی CPU قابل اجرا است. در دات نت این مرحله به CLR یا Common language runtime واگذار شده است تا کار اجرای نهایی کدهای تهیه شده توسط کامپایلر سیشارپ را انجام دهد.
بنابراین زمانیکه در VS.NET سعی در اجرای یک قطعه کد مینمائیم، مراحل ذیل رخ میدهند:
الف) فایلهای سیشارپ پروژه، توسط کامپایلر بارگذاری میشوند.
ب) کامپایلر کدهای این فایلها را پردازش میکند.
ج) سپس چیزی را به نام MSIL تولید میکند.
د) در ادامه فایل خروجی نهایی، با افزودن PE Headers تولید میشود. توسط PE headers مشخص میشود که فایل تولیدی نهایی آیا اجرایی است، یا یک DLL میباشد و امثال آن.
ه) و در آخر، فایل اجرایی تولیدی توسط CLR بارگذاری و اجرا میشود.
MSIL چیست؟
MSIL مخفف Microsoft intermediate language است. به آن CIL یا Common intermediate language هم گفته میشود و این دقیقا همان کدی است که توسط CLR خوانده و اجرا میشود. MSIL یک زبان طراحی شده مبتنی بر پشتهها است و بسیار شبیه به سایر زبانهای اسمبلی موجود میباشد.
یک سؤال: آیا قطعه کدهای ذیل، کدهای IL یکسانی را تولید میکنند؟
namespace FastReflectionTests { public class Test { public void Method1() { var x = 10; var y = 20; if (x == 10) { if (y == 20) { } } } public void Method2() { var x = 10; var y = 20; if (x == 10 && y == 20) { } } } }
.class public auto ansi beforefieldinit FastReflectionTests.Test extends [mscorlib]System.Object { // Methods .method public hidebysig instance void Method1 () cil managed { // Method begins at RVA 0x3bd0 // Code size 17 (0x11) .maxstack 2 .locals init ( [0] int32 x, [1] int32 y ) IL_0000: ldc.i4.s 10 IL_0002: stloc.0 IL_0003: ldc.i4.s 20 IL_0005: stloc.1 IL_0006: ldloc.0 IL_0007: ldc.i4.s 10 IL_0009: bne.un.s IL_0010 IL_000b: ldloc.1 IL_000c: ldc.i4.s 20 IL_000e: pop IL_000f: pop IL_0010: ret } // end of method Test::Method1 .method public hidebysig instance void Method2 () cil managed { // Method begins at RVA 0x3bf0 // Code size 17 (0x11) .maxstack 2 .locals init ( [0] int32 x, [1] int32 y ) IL_0000: ldc.i4.s 10 IL_0002: stloc.0 IL_0003: ldc.i4.s 20 IL_0005: stloc.1 IL_0006: ldloc.0 IL_0007: ldc.i4.s 10 IL_0009: bne.un.s IL_0010 IL_000b: ldloc.1 IL_000c: ldc.i4.s 20 IL_000e: pop IL_000f: pop IL_0010: ret } // end of method Test::Method2 .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x3c0d // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Test::.ctor } // end of class FastReflectionTests.Test
این کدها در حالت کامپایل Release تهیه شدهاند و در این حالت، کامپایلر یک سری بهینه سازیهایی را جهت بهبود سرعت و کاهش تعداد OpCodes مورد نیاز برای اجرا برنامه، اعمال میکند.
بررسی OpCodes مقدماتی
الف) OpCodes ریاضی
مانند Add، Sub، Mul و Div
ب) OpCodes کنترل جریان برنامه
مانند Jmp، Beq، Bge، Ble، Bne، Call و Ret
برای پرش به یک برچسب، بررسی تساوی و بزرگتر یا کوچک بودن، فراخوانی متدها و بازگشت دادن مقادیر
ج) OpCodes مدیریت آرگومانها
مانند Ldarg، Ldarg_0 تا Ldarg_3 ، Ldc_I4 و Ldc_I4_1 تا Ldc_I4_8
برای بارگذاری آرگومانها و همچنین بارگذاری مقادیر قرار گرفته شده بر روی پشته ارزیابی.
برای توضیحات بهتر این موارد میتوان کدهای IL فوق را بررسی کرد:
IL_0000: ldc.i4.s 10 IL_0002: stloc.0 IL_0003: ldc.i4.s 20 IL_0005: stloc.1 IL_0006: ldloc.0 IL_0007: ldc.i4.s 10 IL_0009: bne.un.s IL_0010 IL_000b: ldloc.1 IL_000c: ldc.i4.s 20 IL_000e: pop IL_000f: pop
Stack چیست و MSIL چگونه عمل میکنید؟
Stack یکی از انواع بسیار متداول ساختار دادهها است و اگر بخواهیم خارج از دنیای رایانهها مثالی را برای آن ارائه دهیم میتوان به تعدادی برگه کاغذ که بر روی یکدیگر قرار گرفتهاند، اشاره کرد. زمانیکه نیاز باشد تا برگهای از این پشته برداشته شود، باید از بالاترین سطح آن شروع کرد که به آن LIFO یا Last in First out نیز گفته میشود. چیزی که آخر از همه بر روی پشته قرار میگیرد، در ابتدا برداشته و خارج خواهد شد.
در دات نت، برای قرار دادن اطلاعات بر روی Stack از متد Push و برای بازیابی از متد Pop استفاده میشود. استفاده از متد Pop، سبب خذف آن شیء از پشته نیز میگردد.
MSIL نیز یک Stack based language است. MSIL برای مدیریت یک سری از موارد از Stack استفاده میکند؛ مانند: پارامترهای متدها، مقادیر بازگشتی و انجام محاسبات در متدها. OpCodes کار قرار دادن و بازیابی مقادیر را از Stack به عهده دارند. به تمام اینها در MSIL، پشته ارزیابی یا Evaluation stack نیز میگویند.
یک مثال: فرض کنید میخواهید جمع 5+10 را توسط MSIL شبیه سازی کنیم.
الف) مقدار 5 بر روی پشته ارزیابی قرار داده میشود.
ب) مقدار 10 بر روی پشته ارزیابی قرار داده میشود. این مورد سبب میشود که 5 یک سطح به عقب رانده شود. به این ترتیب اکنون 10 بر روی پشته است و پس از آن 5 قرار خواهد داشت.
ج) سپس OpCode ایی مساوی Add فراخوانی میشود.
د) این OpCode سبب میشود تا دو مقدار موجود در پشته Pop شوند.
ه) سپس Add، حاصل عملیات را مجددا بر روی پشته قرار میدهد.
یک استثناء
در MSIL برای مدیریت متغیرهای محلی تعریف شده در سطح یک تابع، از Stack استفاده نمیشود. این مورد شبیه سایر زبانهای اسمبلی است که در آنها میتوان مقادیر را در برچسبها یا رجیسترهای خاصی نیز ذخیره کرد.
ویژگی های جدید dotNET Core 2.1
Earlier this week, Microsoft published the roadmap for .NET Core 2.1, ASP.NET Core 2.1 and EF Core 2.1, expected to be out in the first quarter of 2018. The team also talked about several new features with this new release. This release is more of a feedback-oriented release based on .NET Core 2.0 release. The.NET Core 2.0 is a huge success and already more than half a million developers are now using .NET Core 2.0. All thanks to .NET Standard 2.0 release . In this post find out about the new features of .NET Core 2.1.
TypeScript 4.3 منتشر شد
Separate Write Types on Properties
override and the --noImplicitOverride Flag
Template String Type Improvements
ECMAScript #private Class Elements
ConstructorParameters Works on Abstract Classes
Contextual Narrowing for Generics
Always-Truthy Promise Checks
static Index Signatures
.tsbuildinfo Size Improvements
Lazier Calculations in --incremental and --watch Compilations
Import Statement Completions
Editor Support for @link Tags
Go-to-Definition on Non-JavaScript File Paths
Breaking Changes
What’s Next?