مطالب
اتصال Node.js به SQL Server با استفاده از Edge.js
اگر خواسته باشید که با استفاده از Node.js به SQL Server متصل شوید، احتمالا متوجه شده‌اید ماژولی که مایکروسافت منتشر کرده است، ناقص بوده و به صورت پیش نمایش است که بسیاری از ویژگی‌ها و مسائل مهم، در آن در نظر گرفته نشده است.

یکی دیگر از ماژول‌هایی که امکان اتصال Node.js را به SQL Server ممکن می‌کند، Edge.js است. Edge.js یک ماژول Node.js است که امکان اجرای کدهای دات نت را در همان پروسه توسط Node.js فراهم می‌کند. این مسئله، توسعه دهندگان Node.js را قادر می‌سازد تا از فناوری‌هایی که به صورت سنتی استفاده‌ی از آنها سخت یا غیر ممکن بوده است را به راحتی استفاده کنند. برای نمونه:
  • SQL Server
  • Active Directory
  • Nuget packages
  • استفاده از سخت افزار کامپیوتر (مانند وب کم، میکروفن و چاپگر)


نصب Node.js

اگر Node.js را بر روی سیستم خود نصب ندارید، می‌توانید از اینجا آن را دانلود کنید. بعد از نصب برای اطمینان از کارکرد آن، command prompt را باز کرده و دستور زیر را تایپ کنید:

node -v
شما باید نسخه‌ی نصب شده‌ی Node.js را مشاهده کنید.

ایجاد پوشه پروژه

سپس پوشه‌ای را برای پروژه Node.js خود ایجاد کنید. مثلا با استفاده از command prompt و دستور زیر:

md \projects\node-edge-test1
cd \projects\node-edge-test1

نصب Edge.js

Node با استفاده از package manager خود دانلود و نصب ماژول‌ها را خیلی آسان کرده است. برای نصب، در command prompt عبارت زیر را تایپ کنید:

npm install edge
npm install edge-sql
فرمان اول باعث نصب Edge.js و دومین فرمان سبب نصب پشتیبانی از SQL Server می‌شود.

Hello World

ایجاد یک فایل متنی با نام server.js و نوشتن کد زیر در آن:
var edge = require('edge');

// The text in edge.func() is C# code
var helloWorld = edge.func('async (input) => { return input.ToString(); }');

helloWorld('Hello World!', function (error, result) {
    if (error) throw error;
    console.log(result);
});
حالا برای اجرای این Node.js application از طریق command prompt کافی است به صورت زیر عمل کنید:
node server.js
همانطور که مشاهده می‌کنید "!Hello World" در خروجی چاپ شد.

ایجاد پایگاه داده تست

در مثال‌های بعدی، نیاز به یک پایگاه داده داریم تا query‌ها را اجرا کنیم. در صورتی که SQL Server بر روی سیستم شما نصب نیست، می‌توانید نسخه‌ی رایگان آن را از اینجا دانلود و نصب کنید. همچنین SQL Management Studio Express را نیز نصب کنید.

  1. در SQL Management Studio، یک پایگاه داده را با نام node-test با تنظیمات پیش فرض ایجاد کنید.
  2. بر روی پایگاه داده node-test راست کلیک کرده و New Query را انتخاب کنید.
  3. اسکریپت زیر را copy کرده و در آنجا paste کنید، سپس بر روی Execute کلیک کنید.
IF EXISTS(SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('SampleUsers')) BEGIN; DROP TABLE SampleUsers; END; GO

CREATE TABLE SampleUsers ( Id INTEGER NOT NULL IDENTITY(1, 1), FirstName VARCHAR(255) NOT NULL, LastName VARCHAR(255) NOT NULL, Email VARCHAR(255) NOT NULL, CreateDate DATETIME NOT NULL DEFAULT(getdate()), PRIMARY KEY (Id) ); GO

INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Orla','Sweeney','nunc@convallisincursus.ca','Apr 13, 2014');
INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Zia','Pickett','porttitor.tellus.non@Duis.com','Aug 31, 2014');
INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Justina','Ayala','neque.tellus.imperdiet@temporestac.com','Jul 28, 2014');
INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Levi','Parrish','adipiscing.elit@velarcueu.com','Jun 21, 2014');
INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Pearl','Warren','In@dignissimpharetra.org','Mar 3, 2014');
نتیجه‌ی اجرای کد بالا، ایجاد جدولی با نام SampleUsers و درج 5 رکورد در آن می‌شود.

تنظیمات ConnectionString

قبل از استفاده از Edge.js با SQL Server، باید متغیر محیطی (environment variable) با نام EDGE_SQL_CONNECTION_STRING را تعریف کنید.

set EDGE_SQL_CONNECTION_STRING=Data Source=localhost;Initial Catalog=node-test;Integrated Security=True
این متغیر تنها برای command prompt جاری تعریف شده است و با بستن آن از دست می‌رود. در صورتیکه از Node.js Tools for Visual Studio استفاده می‌کنید، نیاز به ایجاد یک متغیر محیطی دائمی و راه اندازی مجدد VS دارید. همچنین در صورتیکه بخواهید متغیر محیطی دائمی ایجاد کنید، فرمان زیر را اجرا کنید:
SETX EDGE_SQL_CONNECTION_STRING "Data Source=localhost;Initial Catalog=node-test;Integrated Security=True"


روش اول: اجرای مستقیم SQL Server Query در Edge.js

فایلی با نام server-sql-query.js را ایجاد کرده و کد زیر را در آن وارد کنید:

var http = require('http');
var edge = require('edge');
var port = process.env.PORT || 8080;

var getTopUsers = edge.func('sql', function () {/*
    SELECT TOP 3 * FROM SampleUsers ORDER BY CreateDate DESC
*/});

function logError(err, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.write("Error: " + err);
    res.end("");
}    

http.createServer(function (req, res) {
    res.writeHead(200, { 'Content-Type': 'text/html' });

    getTopUsers(null, function (error, result) {
        if (error) { logError(error, res); return; }
        if (result) {
            res.write("<ul>");
            result.forEach(function(user) {
                res.write("<li>" + user.FirstName + " " + user.LastName + ": " + user.Email + "</li>");
            });
            res.end("</ul>");
        }
        else {
        }
    });
}).listen(port);
console.log("Node server listening on port " + port);
سپس با استفاده از command prompt، فرمان زیر را اجرا کنید:
node server-sql-query.js
حال مرورگر خود را باز و سپس آدرس http://localhost:8080 را باز کنید. در صورتی که همه چیز به درستی انجام گرفته باشد لیستی از 3 کاربر را خواهید دید.

روش دوم: اجرای کد دات نت برای SQL Server Query

Edge.js تنها از دستورات Update، Insert، Select و Delete پشتیبانی می‌کند. در حال حاضر از store procedures و مجموعه‌ای از کد SQL پشتیبانی نمی‌کند. بنابراین، اگر چیزی بیشتر از عملیات CRUD می‌خواهید انجام دهید، باید از دات نت برای این کار استفاده کنید.

یادتان باشد، همیشه async

مدل اجرایی Node.js به صورت یک حلقه‌ی رویداد تک نخی است. بنابراین این بسیار مهم است که کد دات نت شما به صورت async باشد. در غیر اینصورت یک فراخوانی به دات نت سبب مسدود شدن و ایجاد خرابی در Node.js می‌شود.

ایجاد یک Class Library

اولین قدم، ایجاد یک پروژه Class Library در Visual Studio که خروجی آن یک فایل DLL است و استفاده از آن در Edge.js است. پروژه Class Library با عنوان EdgeSampleLibrary ایجاد کرده و فایل کلاسی با نام Sample1 را به آن اضافه کنید و سپس کد زیر را در آن وارد کنید:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;

namespace EdgeSampleLibrary
{
     public class Sample1
    {
        public async Task<object> Invoke(object input)
        {
            // Edge marshalls data to .NET using an IDictionary<string, object>
            var payload = (IDictionary<string, object>) input;
            var pageNumber = (int) payload["pageNumber"];
            var pageSize = (int) payload["pageSize"];
            return await QueryUsers(pageNumber, pageSize);
        }

        public async Task<List<SampleUser>> QueryUsers(int pageNumber, int pageSize)
        {
            // Use the same connection string env variable
            var connectionString = Environment.GetEnvironmentVariable("EDGE_SQL_CONNECTION_STRING");
            if (connectionString == null)
                throw new ArgumentException("You must set the EDGE_SQL_CONNECTION_STRING environment variable.");

            // Paging the result set using a common table expression (CTE).
            // You may rather do this in a stored procedure or use an 
            // ORM that supports async.
            var sql = @"
DECLARE @RowStart int, @RowEnd int;
SET @RowStart = (@PageNumber - 1) * @PageSize + 1;
SET @RowEnd = @PageNumber * @PageSize;

WITH Paging AS
(
    SELECT  ROW_NUMBER() OVER (ORDER BY CreateDate DESC) AS RowNum,
            Id, FirstName, LastName, Email, CreateDate
    FROM    SampleUsers
)
SELECT  Id, FirstName, LastName, Email, CreateDate
FROM    Paging
WHERE   RowNum BETWEEN @RowStart AND @RowEnd
ORDER BY RowNum;
";
            var users = new List<SampleUser>();

            using (var cnx = new SqlConnection(connectionString))
            {
                using (var cmd = new SqlCommand(sql, cnx))
                {
                    await cnx.OpenAsync();

                    cmd.Parameters.Add(new SqlParameter("@PageNumber", SqlDbType.Int) { Value = pageNumber });
                    cmd.Parameters.Add(new SqlParameter("@PageSize", SqlDbType.Int) { Value = pageSize });

                    using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection))
                    {
                        while (await reader.ReadAsync())
                        {
                            var user = new SampleUser
                            {
                                Id = reader.GetInt32(0), 
                                FirstName = reader.GetString(1), 
                                LastName = reader.GetString(2), 
                                Email = reader.GetString(3), 
                                CreateDate = reader.GetDateTime(4)
                            };
                           users.Add(user);
                        }
                    }
                }
            }
            return users;
        } 
    }

    public class SampleUser
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public DateTime CreateDate { get; set; }
    }
}
سپس ذخیره و کامپایل کنید. فایل DLL خروجی که در مسیر
[project]/bin/Debug/EdgeSampleLibrary.dll
قرار دارد را در پوشه‌ی پروژه Node کپی کنید. فایل جدیدی را با نام server-dotnet-query.js در پروژه Node ایجاد کنید و کد زیر را در آن وارد کنید:
var http = require('http');
var edge = require('edge');
var port = process.env.PORT || 8080;

// Set up the assembly to call from Node.js 
var querySample = edge.func({ assemblyFile: 'EdgeSampleLibrary.dll', typeName: 'EdgeSampleLibrary.Sample1', methodName: 'Invoke' });

function logError(err, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write("Got error: " + err); res.end(""); }

http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/html' });

    // This is the data we will pass to .NET
    var data = { pageNumber: 1, pageSize: 3 };

    // Invoke the .NET function
    querySample(data, function (error, result) {
        if (error) { logError(error, res); return; }
        if (result) {
            res.write("<ul>");
            result.forEach(function(user) {
                res.write("<li>" + user.FirstName + " " + user.LastName + ": " + user.Email + "</li>");
            });
            res.end("</ul>");
        }
        else {
            res.end("No results");
        }
    });

}).listen(port);

console.log("Node server listening on port " + port);
سپس از طریق command prompt آن را اجرا کنید:
node server-dotnet-query.js
حال مرورگر خود را باز کرده و به آدرس http://localhost:8080 بروید. در صورتیکه همه چیز به درستی انجام گرفته باشد، لیستی از 3 کاربر را خواهید دید. مقادیر pageNumber و pageSize را در فایل جاوااسکریپت تغییر دهید و تاثیر آن را بر روی خروجی مشاهده کنید.
 
نکته: برای ایجاد pageNumber و pageSize داینامیک با استفاده از ارسال مقادیر توسط QueryString، می‌توانید از ماژول connect استفاده کنید.
اشتراک‌ها
تفاوت های int ، bigint ، smallint ، tinyint - در محاسبات مهم ، دقت کنید!!!
When you use the +, -, *, /, or % arithmetic operators to perform implicit or explicit conversion of int, smallint, tinyint, or bigint constant values to the float, real, decimal or numeric data types, the rules that SQL Server applies when it calculates the data type and precision of the expression results differ depending on whether the query is autoparameterized or not.
تفاوت های int ، bigint ، smallint ، tinyint  - در محاسبات مهم ، دقت کنید!!!
اشتراک‌ها
SQL Server Language Extensions دات نتی

This sample shows you how to use SQL Server Language Extensions to create a .NET Core C# program that receives two columns (ID and text) from SQL Server and a regular expression as an input parameter. The class returns two columns back to SQL Server (ID and text). 

SQL Server Language Extensions دات نتی
اشتراک‌ها
آشنایی با Shortcutهای مهم و کاربردی در SQL Server 2012
ا زیاد شدن تعداد نرم افزارها یکی از مشکلات کسانی (البته مشکل هم نمی‌شود گفت) که با SQL Server کار می‌کنند عدم آشنایی با Shortcut Keyهای مهم و کاربردی SQL Server می‌باشد. در این مقاله سعی کردم که shortcutهای مهم و کاربری جهت کار با Management Studio را استخراج و در اختیار دوستان قرار دهم...
آشنایی با Shortcutهای مهم و کاربردی در SQL Server 2012
مطالب
مدیریت کار تیمی با SQL Server

پس از انتشار جزوه‌ی SVN در حدود دو سال قبل، ایمیل در این مورد زیاد داشتم. یکی از سؤالات هم این بود که: "چگونه از SVN جهت مدیریت نگارش‌های مختلف یک بانک اطلاعاتی اس کیوال سرور در یک تیم استفاده کنیم؟ (منظور مدیریت schema است)" و من هم پاسخ مناسبی برای این مورد نداشتم چون کلاینت‌های SVN حداقل با Management studio یکپارچه نمی‌شود (بر خلاف ابزارهای موجود برای VS.NET مانند VisualSVN ، AnkhSVN و غیره). صد البته می‌شود از آن همانند اعمال نگارش به یک فایل Text معمولی مانند فایل‌های SQL استفاده کرد، اما خوب ...

و خبر خوب اینکه شرکت معظم RedGate چند روز قبل یک کتاب رایگان را در این مورد منتشر کرده است:



سرفصل‌های این کتاب
Chapter 1: Writing Readable SQL
Chapter 2: Documenting your Database
Chapter 3: Change Management and Source Control
Chapter 4: Managing Deployments
Chapter 5: Testing Databases
Chapter 6: Reusing T-SQL Code
Chapter 7: Maintaining a Code Library
Chapter 8: Exploring your Database Schema
Chapter 9: Searching DDL and Build Scripts
Chapter 10: Automating CRUD
Chapter 11: SQL Refactoring

دریافت

نظرات مطالب
Embed کردن SQL Server Express 2008 در یک برنامه
سلام، ببینید من ورژن‌های متعددی که برای دانلود نسخه 2012 قرار داده شده رو به همراه حجمشون پایین نوشتم. به عنوان مبتدی می‌خواستم بدونم چه وقت از کدام یک از اینها استفاده میشه؟
یک حالتی هست که ویژوال استودیو از من می‌خواد نسخه اکسپرس رو نصب کنم، خوب نسخه ای با حجم و امکانات بالا رو نصب می‌کنم. یک حالتی هم هست که بصورت توکار در یک برنامه قرار داده میشه که کاربر نهایی در اجرای برنامه به مشک برنخوره، حالا چطور متوجه بشیم که کدوم نسخه برای کاربر نهایی مناسبه.
تشکر
SQL Server Express with Tools (with LocalDB, Includes the database engine and SQL Server Management Studio Express) 1.4G
SQL Server Management Studio (Tools only) 939MB
SQL Server Express LocalDB (MSI installer) 24MB
SQL Server Express with Advanced Services (contains the database engine, Express Tools, Reporting Services, and Full Text Search) 1.7G
SQL Server Express (Containing only the database engine) 133MB 
مطالب
بررسی کارآیی کوئری‌ها در SQL Server - قسمت چهارم - شاخص‌های مهم اطلاعات آماری کوئری‌ها
تا اینجا با روش‌های مختلف جمع آوری اطلاعات آماری مرتبط با کوئری‌های اجرا شده‌ی در SQL Server آشنا شدیم. در این قسمت قصد داریم بررسی کنیم این اطلاعات جمع آوری شده، چه مفاهیمی را در بر دارند و مهم‌ترین‌های آن‌ها کدامند؟


شاخص‌های مهم بررسی کارآیی کوئری‌ها

در ابتدای بررسی هر کوئری، باید 4 شاخص بسیار مهم، مدنظر باشند:
- مدت زمان اجرای کوئری: هرچند بررسی مدت زمان اجرای کوئری، شاخص مهمی‌است، اما الزاما حاوی اطلاعات مفیدی در مورد آن کوئری نیست. برای مثال اگر یک کوئری زیاد طول می‌کشد، حتما به معنای وجود مشکلی با آن نیست؛ ممکن است اطلاعات زیادی را واکشی می‌کند یا ممکن است توسط عاملی سد شده‌است. در این موارد هرچند مشکلاتی وجود دارند، اما مستقیما مرتبط با آن کوئری نیستند.
- میزان مصرف CPU: میزان کاری که باید توسط CPU انجام شود تا کوئری به نتیجه برسد.
- I/O: در SQL Server می‌توان هم physical I/O و هم logical I/O را بررسی کرد. برای مثال اگر اطلاعات مورد درخواست توسط کوئری هم اکنون در حافظه موجود باشند، نیازی به physical I/O پرهزینه نخواهد بود و در مقابل آن logical I/O کم هزینه‌تر است.
- میزان مصرف حافظه

در کل هر کدام از این شاخص‌ها اگر دارای مقدار بالایی باشند، بیانگر وجود مشکلی است.


مروری بر ابزارهای مختلف اندازه‌گیری شاخص‌های کارآیی

Management studio
درون Management studio می‌توان اطلاعات مرتبط با یک کوئری را به صورت زنده مشاهده کرد. البته این اطلاعات صرفا مرتبط با یک کوئری و یا تعدادی مشخص هستند؛ چون باید کوئری را به صورت دستی درون این برنامه اجرا کرد و سپس اطلاعات اجرای کوئری‌ها را دریافت نمود. اطلاعات آماری که توسط آن نیز ارائه می‌شود محدودیت‌هایی دارد. برای مثال مدت زمان اجرای کوئری و یا تعداد رکوردهای تحت تاثیر قرار گرفته شده را می‌توان مشاهده کرد. اما به اندازه‌ی اطلاعات ارائه شده‌ی در یک execution plan کامل نیست. به علاوه بازگشت اطلاعات حاصل از اجرای کوئری‌ها درون این برنامه، سربار خودش را داشته و سبب کند شدن برنامه می‌شود. در آخر اطلاعات ارائه شده‌ی توسط آن‌را نیز باید از قسمت‌های مختلفی جمع آوری و به صورت دستی ذخیره کرد.

Extended Events
توسط Extended Events نیز می‌توان همانند Management studio، اطلاعات آماری یک تک کوئری و یا یک batch را جمع آوری کرد؛ اما پس از ایجاد و تنظیم آن، به صورت خودکار اجرا می‌شود. در حین تعریف یک سشن Extended Events می‌توان شاخص‌های خاصی را انتخاب کرد و یا شرط‌های دقیقی را اعمال کرد. خروجی آن نیز به صورت خودکار در یک فایل ذخیره می‌شود.

Dynamic management objects
با استفاده از DMO's از نتایج آماری مرتبط با تک کوئری‌ها، به نتایج تجمعی حاصل از اجرای آن‌ها می‌رسیم. این نتایج نیز در plan cache ذخیره می‌شوند. به این معنا که اگر کش، تخلیه (با اجرای دستور DBCC FREEPROCCACHE) و یا سرور ری‌استارت شود، این اطلاعات از دست خواهند رفت. هدف آن بیشتر رفع اشکال کوئری‌هایی است که هم اکنون در حال اجرا هستند. اگر نیاز به اطلاعات دوره‌ای را داشته باشید، نیاز خواهید داشت تا با تهیه‌ی snapshotهایی از بانک اطلاعاتی، این تاریخچه را تکمیل کنید. به همین جهت Query Store ارائه شده‌است تا نیازی به اینکار نباشد.

Query Store
Query Store کار ذخیره سازی متن plan و آمار تجمعی مرتبط با آن‌را به صورت خودکار انجام می‌دهد و آن‌را درون بانک اطلاعاتی کاربر ذخیره می‌کند. به همین جهت با خالی شدن کش، برخلاف DMO's، اطلاعات آن حذف نمی‌شود.


مثالی از روش‌های مختلف جمع آوری اطلاعات آماری حاصل از اجرای کوئری‌ها در SQL Server

در ادامه قصد داریم با مثالی، خلاصه‌ای را از سه قسمتی که تاکنون بررسی کردیم، ارائه دهیم. برای این منظور ابتدا رویه‌ی ذخیره شده‌ی زیر را ایجاد می‌کنیم:
USE [WideWorldImporters];
GO

DROP PROCEDURE IF EXISTS [Application].[usp_GetPersonInfo];
GO

CREATE PROCEDURE [Application].[usp_GetPersonInfo]
    (@PersonID INT)
AS

SELECT
    [p].[FullName],
    [p].[EmailAddress],
    [c].[FormalName]
FROM [Application].[People] [p]
    LEFT OUTER JOIN [Application].[Countries] [c]
    ON [p].[PersonID] = [c].[LastEditedBy]
WHERE [p].[PersonID] = @PersonID;
GO
کار آن دریافت اطلاعات یک کاربر بر اساس ID او می‌باشد.

سپس یک سشن Extended event را با نام QueryPerf ایجاد می‌کنیم:
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 EVENT sqlserver.query_post_execution_showplan
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=ON,STARTUP_STATE=OFF);
GO
این سشن به رخ‌دادهای sql_statement_completed، sp_statement_completed و query_post_execution_showplan، اگر طول مدت آن کوئری بیش از 1 میلی ثانیه باشد، واکنش نشان می‌دهد. نتیجه‌ی نهایی را نیز در پوشه‌ی C:\Temp\QueryPerf ذخیره می‌کند (این پوشه را باید به صورت دستی ایجاد کنید).

در ادامه Query Store را نیز بر روی بانک اطلاعاتی WideWorldImporters فعال کرده و همچنین اگر اطلاعاتی از پیش در آن وجود دارند، پاک می‌شود.
USE [master];
GO

ALTER DATABASE [WideWorldImporters] SET QUERY_STORE = ON;
GO

ALTER DATABASE [WideWorldImporters] SET QUERY_STORE (
OPERATION_MODE = READ_WRITE,
CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 30),
DATA_FLUSH_INTERVAL_SECONDS = 60,
INTERVAL_LENGTH_MINUTES = 5,
MAX_STORAGE_SIZE_MB = 100,
QUERY_CAPTURE_MODE = ALL,
SIZE_BASED_CLEANUP_MODE = AUTO,
MAX_PLANS_PER_QUERY = 200);
GO

ALTER DATABASE [WideWorldImporters] SET QUERY_STORE CLEAR;
GO

سپس هر آنچه را که در plan cache نیز وجود دارد، حذف می‌کنیم:
DBCC FREEPROCCACHE;
GO

اکنون سشن QueryPerf را که پیشتر ایجاد کردیم، آغاز می‌کنیم:
ALTER EVENT SESSION [QueryPerf]
ON SERVER
STATE = START;
GO
نتیجه‌ی آن‌را در قسمت management->extended events، با سبز شدن آیکن QueryPerf می‌توانید مشاهده کنید.


در ادامه چون می‌خواهیم نتایج آماری را در management studio نیز مشاهده کنیم، ابتدا جمع آوری شاخص‌های آماری را در یک پنجره‌ی جدید new query، فعال می‌کنیم:
SET STATISTICS IO ON;
GO
SET STATISTICS TIME ON;
GO
SET STATISTICS XML ON;
GO

همچنین در منوی Query، گزینه‌ی Include client statistics را نیز انتخاب می‌کنیم تا مشخص شود که آیا عملیات insert/update/delete انجام شده‌است. چه تعداد ردیف تحت تاثیر اجرای این کوئری قرار گرفته‌اند. چه تعداد تراکنش انجام شده‌است. همچنین اطلاعات آماری شبکه و زمان نیز ارائه شوند.

پس از این تنظیمات، اکنون نوبت به اجرای کوئری‌های زیر رسیده‌است که یکی پارامتری است و دیگری AdHoc:
USE [WideWorldImporters];
GO

EXECUTE [Application].[usp_GetPersonInfo] 1234;
GO

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';
GO
با اجرای آن، در management studio، برگه‌های messages و client statistics ظاهر می‌شوند که هر کدام اینبار اطلاعات آماری اجرای این کوئری را به همراه دارند. همچنین در قسمت results، امکان مشاهده‌ی query plan، به علت فعال بودن اطلاعات آماری XML، وجود دارد.




سپس سشن QueryPerf را متوقف و حذف می‌کنیم:
ALTER EVENT SESSION [QueryPerf]
ON SERVER
STATE = STOP;
GO

DROP EVENT SESSION [QueryPerf] ON SERVER;
GO
فایل خروجی با پسوند xel آن را که در پوشه‌ی C:\Temp\QueryPerf ذخیره شده‌است، می‌توان در management studio مشاهده کرد. البته در ابتدای نمایش آن، صرفا دو ستون name و timestamp را نمایش می‌دهد که می‌توان با انتخاب هر ردیف آن و سپس انتخاب و کلیک راست بر روی ردیف‌های details آن، گزینه‌ی Show Column in table را انتخاب کرد تا شاخص مدنظر، در ستون‌های گزارش نیز ظاهر شود.


اگر بخواهیم از عملیات صورت گرفته توسط DMO's کوئری بگیریم:
SELECT
    [qs].[last_execution_time],
    [qs].[execution_count],
    [qs].[total_elapsed_time],
    [qs].[total_elapsed_time]/[qs].[execution_count] [AvgDuration],
    [qs].[total_logical_reads],
    [qs].[total_logical_reads]/[qs].[execution_count] [AvgLogicalReads],
    [t].[text],
    [p].[query_plan]
FROM sys.dm_exec_query_stats [qs]
CROSS APPLY sys.dm_exec_sql_text([qs].sql_handle) [t]
CROSS APPLY sys.dm_exec_query_plan([qs].[plan_handle]) [p]
WHERE [t].[text] LIKE '%Countries%';
GO
که در آن تنها ردیف‌هایی که متن کوئری آن‌ها حاوی Countries است، فیلتر شده، به یک چنین خروجی خواهیم رسید:


همانطور که مشاهده می‌کنید، شاخص‌های چهارگانه‌ای که در ابتدای بحث معرفی شدند، در مورد کوئری پارامتری نوشته شده، وضعیت بسیار بهتری نسبت به کوئری AdHoc دوم دارند.

از Query Store هم می‌توان به صورت زیر کوئری گرفت (علاوه بر قسمت رابط کاربری Query Store که ذیل اشیاء مرتبط با بانک اطلاعاتی WideWorldImporters در management studio قابل مشاهده‌است):
USE [WideWorldImporters];
GO

SELECT
    [qsq].[query_id],
    [qst].[query_sql_text],
    CASE
WHEN [qsq].[object_id] = 0 THEN N'Ad-hoc'
ELSE OBJECT_NAME([qsq].[object_id])
END AS [ObjectName],
    [qsp].[plan_id],
    [rs].[count_executions],
    [rs].[avg_logical_io_reads],
    [rs].[avg_duration],
    TRY_CONVERT(XML, [qsp].[query_plan]),
    [rs].[last_execution_time],
    (DATEADD(MINUTE, -(DATEDIFF(MINUTE, GETDATE(), GETUTCDATE())),
[rs].[last_execution_time])) AS [LocalLastExecutionTime]
FROM [sys].[query_store_query] [qsq]
    JOIN [sys].[query_store_query_text] [qst]
    ON [qsq].[query_text_id] = [qst].[query_text_id]
    JOIN [sys].[query_store_plan] [qsp]
    ON [qsq].[query_id] = [qsp].[query_id]
    JOIN [sys].[query_store_runtime_stats] [rs]
    ON [qsp].[plan_id] = [rs].[plan_id]
WHERE [qst].[query_sql_text] LIKE '%Countries%';
GO

مطالب
تنظیمات پیشنهادی حداکثر حافظه‌ی مصرفی اس کیوال سرور

به صورت پیش فرض تنظیمات حافظه‌ی اس کیوال سرور به صورتی است که به آن اجازه می‌دهد تمامی حافظه‌ی مهیای سیستم عامل را مصرف کند! اگر شخصی با این مساله آشنایی نداشته باشد احتمالا تصور خواهد کرد که اس کیوال سرور نشتی حافظه دارد یا کلا مشکلی در سیستم روی داده است که تا این حد مصرف حافظه بالا رفته است.
برای مشاهده‌ی این تنظیمات روی instance سرور مورد نظر کلیک راست کرده و گزینه خواص را انتخاب کنید. سپس در صفحه‌ی باز شده گزینه memory را مشاهده نمائید.
البته این‌کار را با استفاده از دستورات T-SQL هم می‌توان انجام داد:

EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE

EXEC sp_configure 'max server memory (MB)'

EXEC sp_configure 'show advanced options', 0
RECONFIGURE WITH OVERRIDE

نتیجه‌ی آن بر روی سیستم برنامه نویسی من به صورت زیر است:



که البته عمدا آن‌را بر روی یک گیگ تنظیم کرده‌ام تا عملکرد سیستم مختل نشود. (چون اگر غیر از این باشد، تعارفی نداشته و هر آنچه را که صلاح بداند مصرف می‌کند!)
کمی در بلاگ‌های رسمی برنامه نویس‌های اس کیوال سرور در سایت MSDN در این‌‌باره جستجو کردم و نتیجه آن به صورت زیر است:

تنظیمات حداکثر حافظه‌ی مصرفی اس کیوال سرورهای 2005 و 2008
برای یک سیستم عامل 64 بیتی:

Physical RAM MaxMem Setting
2GB 1500
4GB 3200
6GB 4800
8GB 6700
12GB 10600
16GB 14500
24GB 22400
32GB 30000
48GB 45000
64GB 59000


برای سروری 32 بیتی این اعداد حداکثر را تقریبا منهای 300 مگابایت نمائید. (و البته همانطور که مطلع هستید در سیستم عامل‌های سرور 32 بیتی، اگر بیشتر از 2 گیگا بایت رم داشتید سوئیچ 3GB و اگر بیشتر از 4 گیگابایت رم مهیا بود، سوئیچ PAE باید در boot.ini تنظیم شوند. در غیر اینصورت هزینه‌ی سخت افزاری بیهوده‌ای را متحمل شده‌اید، زیرا استفاده‌ی بهینه‌ای از آن در یک سیستم عامل 32 بیتی نخواهد شد)

و این اعداد را همانطور که ذکر شد، در تنظیمات سرور می‌توان وارد نمود ( از طریق management studio ) و یا با استفاده از دستورات T-SQL نیز این امر میسر است: (در مثال زیر حداکثر حافظه مجاز مصرفی به 2300 مگابایت تنظیم می‌شود)

EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE

EXEC sp_configure 'max server memory (MB)', 2300

EXEC sp_configure 'show advanced options', 0
RECONFIGURE WITH OVERRIDE

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


برای مطالعه‌ی بیشتر
http://sqlnerd.blogspot.com/2006/07/memory-use-in-sql-server.html
http://blogs.msdn.com/axperf/archive/2008/03/10/welcome-database-configuration-checklist-part-1.aspx
http://technet.microsoft.com/en-us/library/bb124810.aspx

اشتراک‌ها
SQL Server Management Studio 18.3 منتشر شد

Today we’re announcing the release of SQL Server Management Studio (SSMS) 18.3. For this update, while we added some features, our focus was primarily on fundamentals such as stability, reliability, and performance. 

SQL Server Management Studio 18.3 منتشر شد
مطالب
بررسی کارآیی کوئری‌ها در SQL Server - قسمت دوم - جمع آوری اطلاعات آماری کوئری‌ها توسط Extended Events
همانطور که در قسمت قبل نیز بررسی کردیم، Management Studio برای جمع آوری اطلاعات آماری کوئری‌های زنده بسیار مفید است؛ اما تهیه‌ی آن دستی است. باید کوئری را اجرا کرد و سپس مراحلی را طی نمود تا به نتایج آماری حاصل از کوئری‌ها رسید و همچنین دست آخر باید از نتایج آن نیز یک خروجی دستی را تهیه کرد. روش دیگری نیز برای جمع آوری اطلاعات آماری کوئری‌ها در SQL Server توسط Extended Events/Trace وجود دارد که به ازای هر کوئری، قابل استخراج است. علاوه بر آن می‌توان از Dynamic management objects و یا Query store نیز استفاده کرد. این دو برخلاف Extended Events/Trace، اطلاعات تجمعی گروهی از کوئری‌ها را بازگشت می‌دهند. همچنین در اینجا performance monitor نیز می‌تواند مورد استفاده قرار گیرد؛ اما محدوده‌ی دید آن کل بانک اطلاعاتی است.


Extended Events/Trace

Extended Events، زیر ساخت مدیریت رخ‌دادها در SQL Server است. برای مثال در نگارش 2016 آن بیش‌از 300 رخ‌داد در SQL Server تعریف شده‌اند و زمانیکه در مورد اجرای کوئری‌ها بحث می‌کنیم، این رخ‌دادها بیشتر مدنظر ما هستند:
sql_statement_completed
sp_statement_completed
rpc_completed
sql_batch_completed
کار آن‌ها دریافت اطلاعاتی در مورد logical reads، میزان مصرف CPU، مدت زمان اجرای کوئری‌ها و امثال آن‌ها است. در این بین، دو مورد اول بیش از همه مورد استفاده قرار می‌گیرند.
علاوه بر این‌ها، رخ‌دادهای بسط یافته‌ی زیر را نیز می‌توان مورد استفاده قرار داد:
query_post_compilation_showplan
query_post_execution_showplan
query_pre_execution_showplan
اما به علت هزینه‌بر بودن تولید execution plan به ازای هر کوئری، آنچنان مورد استفاده قرار نمی‌گیرند.


استفاده از 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
این کوئری شبیه به کوئری‌است که در قسمت قبل مورد استفاده قرار گرفت؛ با این تفاوت که به همراه یک * SELECT است که استفاده‌ی از آن توصیه نمی‌شود و در اینجا بیشتر جهت بررسی کارآیی این کوئری، تعریف شده‌است.
سپس یک سشن 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
در این سشن، رخ‌دادهای sp_statement_completed و sql_statement_completed مورد استفاده قرار گرفته‌اند. هر کدام نیز بر اساس مدت زمان اجرای کوئری، فیلتر شده‌اند. در اینجا عدد 1000، یعنی یک میلی ثانیه که عدد بسیار کوچکی است؛ اما برای دمو، مفید است. نتیجه‌ی عملیات نیز در مسیر C:\Temp\QueryPerf ذخیره خواهد شد.

سپس نیاز است تا این سشن را که 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
این کوئری شبیه به رویه‌ی ذخیره شده‌ای است که ایجاد کردیم؛ اما یک کوئری Ad Hoc و غیر پارامتری می‌باشد.

کوئری‌های هر دو پنجره را به صورت مجزایی اجرا کنید. سپس در قسمت 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 را به همراه دارد.