اشتراک‌ها
انتشار R Tools 1.0 برای Visual Studio 2015

This release will be shortly followed by R Tools 1.0 for Visual Studio 2017 in early May. RTVS is a free and open source plug-in that turns Visual Studio into a powerful and productive R development environment. 

انتشار R Tools 1.0 برای Visual Studio 2015
مطالب
بررسی کارآیی کوئری‌ها در SQL Server - قسمت هفتم - بررسی عملگر Nested loop‌ در یک Query Plan
دراین قسمت قصد داریم عملگر nested loop حاصل از نوشتن جوین‌ها را دقیق‌تر بررسی کنیم. یک حلقه‌ی تو در تو، از هر ردیف ورودی (دیتاست خارجی) برای یافتن ردیف‌هایی (دیتاست درونی) که نوع جوین را برآورده می‌کنند، استفاده می‌کند.


بررسی مفهوم دیتاست خارجی و درونی

 ابتدا در 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
این کوئری یک جوین بین جداول OrderLines و Orders را تشکیل داده‌است؛ به همراه کوئری پلن زیر:


در اینجا دیتاست خارجی، همان 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);
اینبار در کوئری پلن تولید شده، index seek بالایی بر روی جدول OrderLines، دیتاست خارجی را تشکیل می‌دهد و index seek دوم بر روی جدول Orders، دیتاست درونی را:



یک نکته: در این تصاویر بجای 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;
این کوئری هرچند به همراه یک جوین نیست، اما دارای کوئری پلنی دارای یک nested loop است:


ایندکس‌هایی که در این کوئری پلن استفاده شده‌اند، شامل موارد پیش‌فرض زیر هستند؛ یکی بر روی 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
)
علت وجود عملگر key lookup بر روی ایندکس PK_Sales_Orders در اینجا این است که ایندکس FK_Sales_Orders_ContactPersonID، ستون‌های کوئری نوشته شده را include نکرده‌است. به همین جهت مجبور شده‌است آن‌ها را از clustered index تعریف شده دریافت کند.
برای بهبود این وضعیت، 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;
به این کوئری پلن دارای index seek بدون nested loop می‌رسیم:


چون ایندکس جدید تعریف شده کاملا کوئری ما را پوشش می‌دهد، دیگر نیازی به ایجاد یک 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
و در این حالت اگر همان کوئری قبلی را مجددا اجرا کنیم، به کوئری پلن دارای index seek زیر خواهیم رسید:

اشتراک‌ها
WebAssembly برای توسعه دهنده‌های دات نت

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
 

WebAssembly برای توسعه دهنده‌های دات نت
اشتراک‌ها
مقدمه ای بر 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. 

مقدمه ای بر Bot Framework مایکروسافت
مطالب دوره‌ها
بررسی مقدماتی مراحل کامپایل یک قطعه کد سی‌شارپ و آشنایی با OpCodes
کامپایلر سی‌شارپ چگونه عمل می‌کند؟

کار یک کامپایلر ترجمه قطعه‌ای از اطلاعات به چیز دیگری است. کامپایلر سی‌شارپ، 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)
            {

            }
        }
    }
}
برای یافتن کدهای MSIL یا IL یک برنامه کامپایل شده می‌توان از ابزارهایی مانند Reflector یا ILSpy استفاده کرد. برای نمونه اگر از برنامه ILSpy استفاده کنیم چنین خروجی IL معادلی را می‌توان مشاهده کرد:
.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
همانطور که مشاهده می‌کنید، کدهای IL با یک برچسب شروع می‌شوند مانند IL_0000. پس از آن OpCodes یا Operation codes قرار دارند. برای مثال ldc کار load constant را انجام می‌دهد. به این ترتیب مقدار ثابت 10 بارگذاری شده و بر روی پشته ارزیابی قرار داده می‌شود و نهایتا در سمت راست، مقادیر را ملاحظه می‌کنید؛ برای مثال مقادیری مانند 10 و 20.
این کدها در حالت کامپایل 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. 

ویژگی های جدید dotNET 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? 

TypeScript 4.3 منتشر شد
اشتراک‌ها
نوشتن JIT Compiler دات نت با #C

We strongly believe in a long-term value of this project. A code base in managed code is more approachable for developers and thus easier to extend and maintain. 

نوشتن JIT Compiler دات نت با #C