مطالب
بررسی کارآیی کوئری‌ها در SQL Server - قسمت هشتم - بررسی عملگرهای Hash Join و Compute Scalar در یک Query Plan
در یک hash join، اطلاعات از دو ورودی نامرتب، دریافت و join می‌شوند که نسبت به merge join، عملیات سنگین‌تری است. برای اینکار، یک hash table را از دیتاست خارجی و یک نمونه‌ی دیگر را بر اساس دیتاست درونی ساخته و سپس کار انطباق ردیف‌ها را انجام می‌دهد.


بررسی عملگر hash join

 ابتدا در management studio از منوی Query، گزینه‌ی Include actual execution plan را انتخاب می‌کنیم. سپس کوئری‌های زیر را اجرا می‌کنیم:
USE [WideWorldImporters];
GO

SET STATISTICS IO ON;
GO


/*
Query with a hash join
*/
SELECT
    [ol].[OrderID],
    [ol].[OrderLineID],
    [ol].[StockItemID],
    [ol].[PickedQuantity],
    [si].[StockItemName],
    [si].[UnitPrice]
FROM [Warehouse].[StockItems] [si]
    JOIN [Sales].[OrderLines] [ol]
    ON [si].[StockItemID] = [ol].[StockItemID];
GO
در اینجا اطلاعات دو جدول StockItems و OrderLines بر روی ستون StockItemID با هم Join شده‌اند و اجرای آن یک چنین کوئری پلنی را تولید می‌کند:


دیتاست بالایی که ضخامت پیکان خارج شده‌ی از آن کمتر است، تعداد ردیف‌های کمتری را نسبت به دیتاست درونی دارد (227 ردیف، در مقابل بیش از 231 هزار ردیف).
با حرکت اشاره‌گر ماوس بر روی هر کدام از ایندکس‌ها، می‌توان با دقت کردن به Output List آن‌ها، دقیقا دریافت که هرکدام، چه ستون‌هایی از کوئری نهایی را تامین می‌کنند:
دیتاست بالایی که از PK_Warehouse_StockItems تامین می‌شود:
ALTER TABLE [Warehouse].[StockItems] ADD  CONSTRAINT [PK_Warehouse_StockItems] PRIMARY KEY CLUSTERED
(
   [StockItemID] ASC
)


دیتاست درونی که از NCCX_Sales_OrderLines تامین می‌شود و یک COLUMNSTORE INDEX است:
CREATE NONCLUSTERED COLUMNSTORE INDEX [NCCX_Sales_OrderLines] ON [Sales].[OrderLines]
(
[OrderID],
[StockItemID],
[Description],
[Quantity],
[UnitPrice],
[PickedQuantity]
)



بهبود کارآیی hash join با فشرده سازی ایندکس‌های آن

ایندکس NCCX_Sales_OrderLines که در کوئری فوق مورد استفاده قرار گرفته، همانطور که در قسمتی از تعریف آن نیز مشخص است، تعداد ستون‌های بیشتری را از آنچه ما نیاز داریم، در بر دارد. در این حالت آیا اگر ایندکس مناسب‌تری را با تعداد ستون کمتری ایجاد کنیم، از آن استفاده می‌کند؟
CREATE NONCLUSTERED INDEX [IX_OrderLines_StockItemID]
ON [Sales].[OrderLines](
[StockItemID] ASC,
[PickedQuantity] ASC,
[OrderID])
ON [PRIMARY];
GO
این ایندکس جدید، نیازهای واقعی کوئری نوشته شده را پوشش می‌دهد و تعداد ستون کمتری را به همراه دارد.
در این حالت اگر کوئری زیر را اجرا کنیم:
SELECT
    [ol].[OrderID],
    [ol].[OrderLineID],
    [ol].[StockItemID],
    [ol].[PickedQuantity],
    [si].[StockItemName],
    [si].[UnitPrice]
FROM [Sales].[OrderLines] [ol]
    JOIN [Warehouse].[StockItems] [si]
    ON [ol].[StockItemID] = [si].[StockItemID]
OPTION
(RECOMPILE);
GO
در کوئری پلن نهایی تفاوتی مشاهده نمی‌شود و باز هم SQL Server، همان COLUMNSTORE INDEX را به ایندکس جدید ترجیح داده‌است. علت اینجا است که ماهیت COLUMNSTORE INDEX‌ها فشرده شده‌است؛ در مقابل NONCLUSTERED INDEXها معمولی که به صورت پیش‌فرض غیر فشرده شده هستند و یک row store می‌باشند.

یک نکته: در این کوئری علت استفاده‌ی از RECOMPILE، وادار کردن SQL server به محاسبه‌ی مجدد کوئری پلن جاری است.

اکنون اگر نگارش فشرده شده‌ی ایندکسی را که ایجاد کردیم، با ذکر گزینه‌ی DATA_COMPRESSION = PAGE تعریف کنیم، چه اتفاقی رخ می‌دهد؟
CREATE NONCLUSTERED INDEX [IX_OrderLines_StockItemID_Compressed]
ON [Sales].[OrderLines](
[StockItemID] ASC,
[PickedQuantity] ASC,
[OrderID])
WITH (DATA_COMPRESSION = PAGE)
ON [PRIMARY];
GO
پس از آن مجددا همان کوئری قبلی را که به همراه RECOMPILE است، اجرا می‌کنیم. اینبار به کوئری پلنی خواهیم رسید که از این ایندکس جدید استفاده می‌کند.

یک نکته: اگر علاقمند بودید تا هزینه‌ی این کوئری‌ها را نسبت به یکدیگر محاسبه و مقایسه کنید، چون یک کوئری معمولی، همواره از آخرین پلن محاسبه شده استفاده می‌کند، اینکار میسر نیست. اما می‌توان با ذکر صریح ایندکس مدنظر توسط راهنمای WITH INDEX، بهینه ساز کوئری‌ها را وارد کرد تا از ایندکسی که ذکر می‌شود، بجای ایندکسی که فکر می‌کند بهتر است، استفاده کند. بنابراین اجرای هر 4 کوئری زیر با هم، 4 کوئری پلن متفاوت را بر اساس ایندکس‌های متفاوتی، محاسبه کرده و نمایش می‌دهد:
SELECT
    [ol].[OrderID],
    [ol].[OrderLineID],
    [ol].[StockItemID],
    [ol].[PickedQuantity],
    [si].[StockItemName],
    [si].[UnitPrice]
FROM [Sales].[OrderLines] [ol]
    JOIN [Warehouse].[StockItems] [si]
    ON [ol].[StockItemID] = [si].[StockItemID]
OPTION
(RECOMPILE);
GO

SELECT
    [ol].[OrderID],
    [ol].[OrderLineID],
    [ol].[StockItemID],
    [ol].[PickedQuantity],
    [si].[StockItemName],
    [si].[UnitPrice]
FROM [Sales].[OrderLines] [ol] WITH (INDEX (IX_Sales_OrderLines_Perf_20160301_02))
    JOIN [Warehouse].[StockItems] [si]
    ON [ol].[StockItemID] = [si].[StockItemID];
GO

SELECT
    [ol].[OrderID],
    [ol].[OrderLineID],
    [ol].[StockItemID],
    [ol].[PickedQuantity],
    [si].[StockItemName],
    [si].[UnitPrice]
FROM [Sales].[OrderLines] [ol] WITH (INDEX (IX_OrderLines_StockItemID))
    JOIN [Warehouse].[StockItems] [si]
    ON [ol].[StockItemID] = [si].[StockItemID];
GO

SELECT
    [ol].[OrderID],
    [ol].[OrderLineID],
    [ol].[StockItemID],
    [ol].[PickedQuantity],
    [si].[StockItemName],
    [si].[UnitPrice]
FROM [Sales].[OrderLines] [ol] WITH (INDEX (IX_OrderLines_StockItemID_Compressed))
    JOIN [Warehouse].[StockItems] [si]
    ON [ol].[StockItemID] = [si].[StockItemID];
GO


بررسی عملگر compute scalar

کار عملگر compute scalar، ارزیابی و محاسبه‌ی یک عبارت است و خروجی آن نیز یک مقدار scalar است؛ مانند functions در SQL Server. مشکلی که با این عملگر وجود دارد این است که هزینه‌ی انجام آن عموما در کوئری پلن ظاهر نمی‌شود (و یا با تخمین نادرستی ظاهر می‌شود) که می‌تواند گمراه کننده باشد. همچنین پلن حاصل، اشیایی را که توسط یک function مورد استفاده قرار می‌گیرند، لحاظ نمی‌کند.

برای نمونه اگر پلن دو کوئری زیر را با هم مقایسه کنیم:
SELECT COUNT(*)
FROM [Sales].[Orders];

SELECT COUNT_BIG (*)
FROM [Sales].[Orders];
تقریبا یکی هستند:


از این جهت که (*)COUNT در SQL server به (*)COUNT_BIG تفسیر شده و اجرا می‌شود. به همین جهت آنچنان تفاوتی در اینجا قابل مشاهده نیست.

اما اگر function زیر را تعریف کنیم:
CREATE FUNCTION dbo.CountProductsSold (
@SalesPersonID INT
) RETURNS INT

AS

BEGIN
    DECLARE @SoldCount INT;

    SELECT @SoldCount = COUNT(DISTINCT [ol].[StockItemID])
    FROM [Sales].[Orders] [o]
        JOIN [Sales].[OrderLines] [ol]
        ON [o].[OrderID] = [ol].[OrderID]
    WHERE [o].[SalespersonPersonID] = @SalesPersonID

    RETURN (@SoldCount);

END
و سپس پلن کوئری که از آن استفاده می‌کند را بررسی نمائیم:
SELECT
    [FullName] AS [SalesPerson],
    [dbo].[CountProductsSold]([PersonID]) AS [NumberOfProductsSold]
FROM [Application].[People]
WHERE [IsSalesperson] = 1;
مشاهده خواهیم کرد که در actual execution plan آن، هزینه‌ی فراخوانی این تابع صفر است و همچنین جزئیاتی از اشیایی که توسط آن فراخوانی شده‌اند نیز ذکر نشده‌است:


یک روش محاسبه‌ی هزینه‌ی فراخوانی این تابع، استفاده از extended events است. روش دیگر آن استفاده از اشیاء DMO's می‌باشد:
SELECT
    [fs].[last_execution_time],
    [fs].[execution_count],
    [fs].[total_logical_reads]/[fs].[execution_count] [AvgLogicalReads],
    [fs].[max_logical_reads],
    [t].[text],
    [p].[query_plan]
FROM sys.dm_exec_function_stats [fs]
CROSS APPLY sys.dm_exec_sql_text([fs].sql_handle) [t]
CROSS APPLY sys.dm_exec_query_plan([fs].[plan_handle]) [p];
این کوئری اطلاعات logical_reads مرتبط با تابع فراخوانی شده را گزارش می‌دهد که ... صفر نیست:


بنابراین compute scalar صورت گرفته دارای هزینه‌ای است که در actual execution plan ظاهر نمی‌شود.
اکنون اگر از منوی Query، گزینه‌ی Include actual execution plan را انتخاب نکنیم و بجای آن گزینه‌ی Display estimated execution plan را انتخاب کنیم، به تصویر زیر خواهیم رسید:


در نیمه‌ی پایینی آن، جزئیات دسترسی‌های تابع فراخوانی شده نیز ذکر می‌شوند. بنابراین استفاده‌ی از estimated execution planها در حین کار با توابع، بسیار مفید است.
اشتراک‌ها
راهنمای مهاجرت از ASP.NET MVC 5 به ASP.NET 5

in this article, I will show how to take a medium-small demo app written using Visual Studio 2013, ASP.NET 4.5, VC 5, and Entity Framework 6 and turn it into a working ASP.NET 5 app employing Visual Studio 2015, MVC 6 and Entity Framework 7. And the new app will happily run on either the .NET 4.6 CLR or the .NET Core CLR. Let's get started.

راهنمای مهاجرت از ASP.NET MVC 5 به ASP.NET 5
اشتراک‌ها
دوره توسعه asp.net mvc

در ادامه دوره مقدماتی mvc که قبلا در سایت  به اشتراک گذاشته شده بود.دوره جدیدی رو مایکروسافت منتشر کرده با عنوان توسعه برنامه‌های MVC که سرفصل‌های آن را در بخش زیر مشاهده می‌کنید:

Mod 01: Introduction to MVC 4
Mod 02: Developing ASP.NET MVC 4 Models
Mod 03: Developing MVC 4 Controllers
Mod 04: Developing ASP.NET MVC 4 Views
Mod 05: Integrating JavaScript and MVC 4
Mod 06: Implementing Web APIs
Mod 07: Deploying to Windows Azure
Mod 08: Visual Studio 2013/MVC 5 Sneak Peek
دوره توسعه asp.net mvc
نظرات مطالب
ASP.NET MVC #23
با عرض سلام و تشکر چند سوال داشتم
1- تنظیم .* در iis5  با خطای wrong extension format مواجه می‌شود آیا راهی برای اصلاح آن وجود دارد.
2- اگر سیستم مسریابی را پسونددار کنیم چگونه به روش مناسبی می‌توانیم همه جای پروژه را کنترل کنیم که مسیریابی دچار مشکل نشود ازجمله در area
3- چگونه بفهمیم که iis یکپارچه است یا کلاسیک
4
- آیا iis7 مد یکپارچه آن در ویندوز سرور 2003 و 2008 قابل نصب است
5-آیا برای ویندوز 8 تنظیم خاصی نیاز دارد . من یک مثال ساده را اجرا کردم و برنامه را بر روی iis قرار دادم با خطای 403 forbidden مربوط به صفحه آغازین مواجه شدم
6- طبق روش گفته شده در آدرس زیر نمی‌توان یک صفحه آغازین دستی درست کرد و در iis تنظیم کرد مثلا deafualt.aspx و در لود آن مستقیما ادامه کار را به داخل مسیریابی mvc  هدایت کرد
http://weblog.west-wind.com/posts/2013/Aug/15/IIS-Default-Documents-vs-ASPNET-MVC-Routes 
نظرات مطالب
ASP.NET MVC #18
سلام ،سال نو مبارک ممنون از پاسخ شما.
من از vs 2013 update1 و win 8.1  استفاده میکنم  و برنامه رو با .NetFrameWork 4.5.1  تست کردم.یعنی شما می‌فرمایید که اگه این بسته‌ی ارتقاع رو نصب کنم مشکل حل میشه؟ (مشکل صدا زدن RoleProvider)
اگر هم تو سیستم لوکال خودم حل شه! به سیستم عامل Host که دسترسی ندارم .بخوام اونم به روز کنم.
من در دات نت 4 که با وب فرم کار می‌کردم همیشه از RoleProvider  سفارشی استفاده می‌کردم و مشکلی نداشت.با مطالعه مقاله شما علاقه مند شدم تا از این به بعد برنامه هامو با MVC توسعه بدم. ولی چون آموزش شما با MVC4 هست و الان که MVC5 عرضه شده سوالات زیادی ذهنم رو مشغول کرده یکی اینکه آیا احتمال داره طی این زمان که از انتشار این مقاله می‌گذره روش‌ها عوض شده و یا روش بهتری برای MVC ارائه شده باشه؟
بازم ممنون از زحمتتتون.
نظرات مطالب
آشنایی و بررسی ابزار Version Manager
با تشکر از کار شما
من این ماژول را نصب کردم اما زمان فعال سازی خطا صادر می‌شود، فایل ActivityLog را بررسی کردم خطای ذیل ثبت شده بود.
<entry>
    <record>5390</record>
    <time>2013/09/09 08:41:39.525</time>
    <type>Error</type>
    <source>VisualStudio</source>
    <description>End package load [VersionManagerPackage]</description>
    <guid>{775E4DAB-A8DC-46E5-A64B-4072C0DD3A42}</guid>
    <hr>80004005 - E_FAIL</hr>
    <errorinfo>Could not load file or assembly 'Microsoft.VisualStudio.Shell.12.0, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.</errorinfo>
  </entry>


اشتراک‌ها
مجموعه‌ای خلاصه شده از معرفی الگوهای طراحی برای استفاده توسعه دهندگان نرم افزار

🔸 الگوهای طراحی راه حل‌های معمولی برای مشکلات رایج در طراحی نرم‌افزار هستند. آنها مانند نقشه‌های از پیش ساخته شده‌ای هستند که می‌توانید آنها را برای حل یک مشکل طراحی تکراری در کد خود سفارشی کنید.

🔸اینطور نیست که مثلا یک الگو را پیدا کنید و آن را در برنامه خود کپی کنید. الگو، یک قطعه کد خاص نیست، بلکه یک مفهوم کلی برای حل یک مشکل خاص است. شما می‌توانید جزئیات الگو را دنبال کنید و راه حلی متناسب با واقعیت‌های برنامه خود را پیاده‌سازی کنید.

🔸 الگوها اغلب با الگوریتم‌ها اشتباه گرفته می‌شوند، زیرا هر دو مفهوم راه حل‌های معمولی برای برخی از مسائل شناخته شده را توصیف می‌کنند. در حالی که یک الگوریتم همیشه مجموعه واضحی از اقدامات را تعریف می‌کند که می‌تواند به هدفی دست یابد، یک الگو راه حل‌های سطح بالا برای مسائل سطح بالا هستند. کد یک الگوی اعمال شده برای دو برنامه مختلف ممکن است متفاوت باشد.

🔸 همیشه منظور هر الگو را در ذهن خود مرور کنید و هنگام برخورد با یک مسئله به دنبال مناسب‌‌ترین الگو بگردید.

🔸 شما نمی‌‌توانید یک الگو را به کار بگیرید مگر آنکه آن را به خوبی فهمیده باشید. بنابراین در اولین گام باید اصول و
الگوهای طراحی را هم به شکل انتزاعی و هم به شکل واقعی خوانده و تمرین کنید. دقت کنید که یک الگو را به شکل‌‌های مختلفی می‌توان پیاده‌سازی کرد. هر چه پیاده سازی‌‌های بیشتری ببینید، به هدف و چگونگی استفاده از آن بهتر مسلط می‌شوید.

راهنمای شروع سریع برای مطالعه الگوهای طراحی 👇🏻

PDF Cards: designpatternscard.pdf

DesignPatterns-online.pdf

مجموعه‌ای خلاصه شده از معرفی الگوهای طراحی برای استفاده توسعه دهندگان نرم افزار
مطالب
خواندنی‌های 5 اردیبهشت

  • - پیش نمایش MySQL 5.4 توسط شرکت سان ارائه شد. این شرکت مدعی است که response times آن 90 درصد نسبت به نگارش قبلی سریعتر شده (+ و +)
  • - سایت GeoCities بسته شد. سایت Google pages هم قرار است تا یکی دو ماه دیگر بسته شود (به عبارت دیگر شکل و شمایل این وبلاگ در آن تاریخ کلا به هم خواهد ریخت چون فایل‌های سایت را در آن‌جا هاست کرده‌ام ... به دریا هم که برویم ...)
مطالب
فشرده سازی اسمبلی‌های دات نت

ابزارهای زیادی برای محافظت و یا فشرده سازی و رمزنگاری اسمبلی‌های دات نت موجود هستند که اکثر آنها تجاری هستند. برنامه netz نمونه‌ای است سورس باز و رایگان که تنها کار فشرده سازی اسمبلی موجود را انجام می‌دهد. همچنین با استفاده از آن سورس اسمبلی شما به‌وسیله برنامه reflector قابل مرور نخواهد بود. هر چند این برنامه سورس باز است و امکان unpack کردن نتیجه آن نیز احتمالا با اندکی سعی میسر خواهد بود اما باز هم یک مرحله پیشرفت محسوب می‌شود! خصوصا اینکه می‌توان برای آن Custom Compression Provider نوشت و برای مثال فایل زیپ شده نهایی را رمزنگاری نیز کرد.

قبل از عمل:



بعد از عمل:


نحوه استفاده:

فشردن کردن یک فایل exe توسط آن
netz app.exe

الحاق کردن فایل zip.dll همراه با فایل exe (بدون نیاز به توزیع فایل zip.dll):
netz -z app.exe

یکی کردن تمام dll های برنامه با فایل exe در قالب یک فایل نهایی:
netz -s app.exe lib1.dll lib2.dll

نکته:
در اینجا به صورت پیش فرض از فایل zip.dll برای فشرده سازی استفاده می‌شود (که برای تمام نگارش‌های دات نت قابل استفاده است). در نگارش‌های جدید دات نت، فشرده سازی نیز به کلاس‌های استاندارد اضافه شده است که امکان استفاده از آن نیز در اینجا مهیا است (و دیگر نیازی به استفاده از zip.dll آن نخواهد بود).
netz.exe -r net20comp.dll  app.exe

نحوه برنامه نویسی یک compression provider سفارشی برای آن در آدرس زیر توضیح داده شده است. (اعمال موارد امنیتی دلخواه و استفاده از آن)
http://madebits.com/netz/compress.php

و موارد دیگری که در راهنمای سایت آن توضیح داده شده‌اند.

مطالب
تعیین Fallback font برای قلم‌های فارسی در WPF

اکثر قلم‌های فارسی، فاقد تعاریف مرتبط با حروف انگلیسی هستند. البته عموم کاربران متوجه این امر نمی‌شوند چون ویندوز دو مفهوم Font Fallback و Font Linking را جهت پوشش glyph های تعریف نشده، در پشت صحنه اعمال خواهد کرد. جزئیات بیشتر در اینجا: (^ و ^)

به صورت خلاصه کار Font Fallback در ویندوز جایگزینی خودکار قلم مورد استفاده است؛ تحت شرایط زیر:
- فونت تعریف شده در برنامه، در سیستم کاربر وجود نداشته باشد.
- تعاریف Glyphهای بکارگرفته شده در متن جاری، در قلم انتخابی وجود نداشته باشند.

در WPF این مساله کاملا قابل کنترل است. قلمی که به صورت خودکار به عنوان جایگزین مطرح می‌شود در قلمی به نام "Global User Interface" تعریف شده است. تعاریف این قلم ترکیبی هم در فایلی به نام GlobalUserInterface.CompositeFont در پوشه فونت‌های سیستم موجود است (برای مثال، مسیر c:\windows\fonts حاوی این فایل متنی است).
اگر این فایل XML را با یک ادیتور متنی باز کنید، مشاهده خواهید کرد که بازه‌های مختلف کاراکترهای یونیکد، به فونت‌های پیش فرضی نگاشت شده‌اند. بنابراین اگر این سؤال وجود دارد که در متن مخلوط فارسی و انگلیسی من، فونت پیش فرض حروف انگلیسی از کجا تامین و مشخص می‌شود، پاسخ را در این فایل می‌توانید مشاهده کنید.

روش دیگری هم برای تعیین Fallback font در WPF وجود دارد. یک مثال:

<Window x:Class="WpfFontTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock
Text="نمایش مخلوطی از متن فارسی و متن English با هم"
Margin="7"
FontFamily="Fonts/BNazanin.ttf#B Nazanin, Comic Sans Ms"
FontSize="25"
FlowDirection="RightToLeft"
VerticalAlignment="Top" HorizontalAlignment="Center" />
</Grid>
</Window>

در این مثال فونت B Nazanin در برنامه قرار داده شده است (embedded font). همچنین در کنار آن پس از علامت کاما، Fallback font مشخص است. به این معنا که تاجایی که میسر است لطفا از فونت B Nazanin برای نمایش متن مورد نظر استفاده شود؛ اگر نشد از قلم Comic Sans Ms استفاده گردد. قلم B Nazanin حاوی تعاریف حروف انگلیسی نیست. بنابراین WPF جهت نمایش آن‌ها از فونت دوم معرفی شده کمک می‌گیرد. توضیحات بیشتر در اینجا: (^)