مطالب
پروسیجرها و شنود پارامترها در SQL Server - قسمت دوم
در ادامه مطلب قبلی، آشنایی با شنود پارامترها در اس کیو ال سرور، جهت بهبود زمان پاسخگویی پروسیجرها یا کوئری‌های پارامتری الزامی است.
اس کیو ال سرور بوسیله ایجاد پلن‌های اجرایی کامپایل شده، سعی در بهینه سازی پروسیجرها دارد. هنگامیکه اس کیو ال سرور یک پروسیجر را کامپایل می‌نماید، به پارامترهای ارسال شده توجه دارد و یک پلن اجرایی را بر اساس پارامترهای ارسالی ایجاد می‌کند. به فرآیند تماشا یا توجه به پارامترهای ارسالی به پروسیجر، شنود پارامترها گفته می‌شود. شنود پارامترها می‌تواند بعضی از اوقات به کاهش کارآیی پلن اجرایی منجر شود؛ مخصوصا زمانیکه پارامترهایی با کاردینالیتی متفاوت، فراخوانی شوند.

شنود پارامتر چیست؟

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

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

مثالی از مصرف شدید I/O بدلیل شنود پارامتر

در ادامه، برای درک بهتر شنود پارامتر، با مثالی خواهید دید که پروسیجر ذیل، باعث مصرف بالای منابع، بر اساس پارامترهای ارسالی خواهد شد. در این مثال دو دسته متفاوت پارامتر برای اجرای پروسیجر ارسال خواهند شد و خواهید دید که فراخوانی دوم، منابع I/O بیشتری را نسبت به فراخوانی اول، مصرف خواهد کرد. در ادامه کدهای جدولی را که پروسیجر قرار است بر روی آن فراخوانی اطلاعات را انجام دهد، می‌بینید.

SET NOCOUNT ON;
DROP TABLE BillingInfo;
CREATE TABLE BillingInfo(
ID INT IDENTITY,
BillingDate DATETIME,
BillingAmt MONEY,
BillingDesc varchar(500));
 
DECLARE @I INT;
DECLARE @BD INT;
SET @I = 0;
WHILE @I < 1000000 
BEGIN
  SET @I = @I + 1;
  SET @BD=CAST(RAND()*10000 AS INT)%3650;
  INSERT BillingInfo (BillingDate, BillingAmt) 
  VALUES (DATEADD(DD,@BD,
    CAST('1999/01/01' AS DATETIME)),
    RAND()*5000);
END 
 
ALTER TABLE BillingInfo 
  ADD  CONSTRAINT [PK_BillingInfo_ID] 
  PRIMARY KEY CLUSTERED (ID);
 
CREATE NONCLUSTERED INDEX IX_BillingDate
  ON dbo.BillingInfo(BillingDate);

در جدول BilingInfo بالا، یک میلیون رکورد با مقادیر BilingDate و BilingAmt به صورت تصادفی ایجاد شده است. بر روی ستون ID، ایندکس خوشه‌ای و ستون ایندکس غیر خوشه‌ای بر روی ستون BilingDate ایجاد شده‌است.

بوسیله پروسیجر زیر هم قرار است اطلاعات درخواستی فراهم شود:

CREATE PROC [dbo].[DisplayBillingInfo]
  @BeginDate DATETIME,
  @EndDate DATETIME
AS
SELECT BillingDate, BillingAmt
  FROM BillingInfo
  WHERE BillingDate between @BeginDate AND @EndDate;
سپس پروسیجر را 2 بار، با مقادیر پارامترهای متفاوتی اجرا می‌کنیم:
SET STATISTICS IO ON;
DBCC FREEPROCCACHE;
EXEC dbo.DisplayBillingInfo 
  @BeginDate = '1999-01-01',  
  @EndDate  = '1999-12-31';  
  
EXEC dbo.DisplayBillingInfo 
  @BeginDate = '2005-01-01',  
  @EndDate  = '2005-01-03';
اطلاعات آماری I/O روشن است و اطلاعات I/O در هر بار اجرا، نمایش داده می‌شود. در خط دوم توسط DBCC FREEPROCCACHE، پلن کش خالی خواهد شد؛ جهت اطمینان از عدم وجود پلن اجرایی مشابهی.
در فراخوانی اول، اطلاعات در بازه یک سال و در فراخوانی دوم، در بازه چند روز، درخواست شده‌اند. همانطور که گفته شد، پلن اجرایی بر اساس فراخوانی اول ایجاد خواهد شد و فراخوانی دوم نیز براساس همین پلن اجرایی ایجاد شده، اجرا می‌شود.


همانطور که مشاهده می‌کنید عملیات Clustered Index Scan، اجرا شده و اطلاعات I/O نیز بشرح زیر است (خط اول فراخوانی اول، خط دوم فراخوانی دوم):
Table 'BillingInfo'. Scan count 1, logical reads 3593, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
 
Table 'BillingInfo'. Scan count 1, logical reads 3593, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
حال ترتیب فراخوانی‌ها را به‌شرح زیر جابجا می‌کنیم:
SET STATISTICS IO ON;
DBCC FREEPROCCACHE;
EXEC dbo.DisplayBillingInfo 
  @BeginDate = '2005-01-01',  
  @EndDate  = '2005-01-03';
  
EXEC dbo.DisplayBillingInfo 
  @BeginDate = '1999-01-01',  
  @EndDate  = '1999-12-31';
در کد بالا ابتدا فراخوانی که بازه کوچکتری دارد اجرا و پلن اجرایی بر اساس آن ایجاد خواهد شد و فراخوانی دوم از پلن کش شده استفاده می‌کند.

اکنون عملیات Index Seek را بجای Index Scan مشاهده می‌کنید. اطلاعات I/O هم بشرح زیر است:

Table 'BillingInfo'. Scan count 1, logical reads 2965, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
 
Table 'BillingInfo'. Scan count 1, logical reads 337040, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
اکنون فراخوانی اول بهینه‌تر اجرا شده و بجای Index Scan از Index Seek استفاده کرده‌است و logical reads آن کاهش یافته‌است. در حالیکه فراخوانی دوم که در بازه یکسال اجرا شده‌است، با عملیات هزینه بر I/O بیشتری نسبت به آزمایش (حدود 100 برابر) انجام شده‌است. انجام این 2 آزمایش، پلن اجرایی متفاوتی را بر اساس پارامترهای ورودی ایجاد کرد و هزینه‌های I/O آن را مشاهده کردید. اکنون درک خوبی را نسبت به این قابلیت و اثرات آن خواهید داشت و در قسمت بعدی به راه حل‌هایی جهت کاهش اثرات منفی آن اشاره خواهد شد.
اشتراک‌ها
محاسبه‌ی میزان پیچیدگی کدهای قسمت‌های مختلف برنامه
// <Name>Aggregate Type Complexity</Name>
from t in Application.Types
 
let aggregateTypeCC = t.MethodsAndContructors.Sum(m => m.CyclomaticComplexity / 10)
let rawCC = t.MethodsAndContructors.Sum(m => m.CyclomaticComplexity)
 
// optional optimization if not comparing rawCC
// where aggregateCC >= 10
 
orderby aggregateTypeCC descending 
select new { t, aggregateTypeCC, rawCC }
محاسبه‌ی میزان پیچیدگی کدهای قسمت‌های مختلف برنامه
مطالب
LocalDB چیست؟

LocalDB نسخه‌ای جدید از Sql server express است که به توسعه دهندگان این اجازه را می‌دهد تا با نصب آن، از نصب کامل دیگر نسخه‌های Sql server جلوگیری نمایند. LocalDB برای برنامه‌هایی که به صورت Local و بر روی یک سیستم اجرا می‌شوند مورد استفاده قرار می‌گیرد. 

مزایای استفاده از این نسخه

  • فایل نصب با حجم بسیار کم. (28.2MB برای نسخه 32 بیتی و 33.7MB برای نسخه 64بیتی)
  • سادگی ( بدون نیاز به انجام تنظیمات خاص بر روی سیستم)
  • اجرا در محیطهایی که کاربر جاری دسترسی مدیریتی ندارد.(برای اجرای آن نیاز به Permissionهای مدیریتی نیست و یک کاربر سطح پایین هم می‌تواند آن را اجرا کند)
  • سادگی نصب
  • همانند Sql server Express سازگاری کاملی با T-Sql دارد. همچنین از Stored Procedureها ، داده‌های جغرافیایی و مکانی ( geometry and geography ها) ، Triggers و View‌ها پشتیبانی می‌کند.
  • سازگاری با Provider معمولی Sql server
  • عدم اجرای سرویس خاصی در حافظه برای مدیریت دیتابیس. پروسس‌های LocalDb هر زمان که نیاز باشد اجرا می‌شوند و هر زمان که به آنها نیاز نداشته باشیم به صورت اتوماتیک متوقف می‌شوند.
  • پشتیبانی از خصوصیت AttachDbFileName  در کانکشن استرینگ جهت استفاده از فایل بانک اطلاعات به صورت مستقیم
  • سرویس پک‌های جدید جهت LocalDB به راحتی برروی نسخه موجود نصب میشوند و نسخه قبلی را به روز رسانی میکنند.
  • نصب یک LocalDB برای همه کاربران یک کامپیوتر
  • پشتیبانی کامل از Silent Installation
  • امکان استفاده از آن توسط Asp.net
  • پشتیبانی از XML (XQuery و XPath) و BLOB
  • پشتیبانی از Ado.net sync framework
  • پشتیبانی از LINQ
  • پشتیبانی از Distributed transactions
  • کانکشن‌های نامحدود (البته به صورت Local)
 
 نیازمندی‌های نصب
  • نیاز به نصب Sql server 2012 native client . این مورد به همراه LocalDB روی سیستم نصب نمیشود
  • نیاز به دسترسی مدیریتی جهت نصب 
  • 140MB فضای خالی دیسک سخت
  • به روز رسانی دات نت فریم ورک 4 به 4.0.2 و یا نسخه‌های بالاتر
محدودیت ها
  • عدم پشتیبانی از Windows xp ، Window server 2003 و Windows 2000
  • عدم امکان نصب نسخه 32 بیتی بر روی ویندوز 64 بیتی (حتما باید نسخه 64 بیتی آن را نصب کنید)
  • فقط می‌توان به صورت Local از آن استفاده کرد. امکان استفاده تحت شبکه وجود ندارد و  فقط به کانکشن‌های Local پاسخ می‌دهد.
  • فقط توسط Sql server 2012 management studio در دسترس می‌باشد. LocalDB را نمی‌توان از طریق Management studio‌های قدیمی مدیریت کرد.
  • عدم پشتیبانی Visual Studio 2010 از LocalDB
  • عدم اجرا بر روی موبایل‌های هوشمند
  • محدودیت سایز بانک اطلاعات :  10GB
  • عدم پشتیبانی از قابلیت FileStream
  • محدودیت استفاده از فقط یک CPU
  • عدم امکان Debuging دستورات Sql در هنگام اتصال به LocalDB
 نحوه نصب
ابتدا Sql server LocalDB را دانلود نمایید. سپس برای نصب آن بر روی سیستم فقط کافی است که فایل نصاب برنامه را اجرا نموده و License مربوطه را قبول نمایید.همچنین در صورت نیاز به Silent Installation کافی است که از دستور زیر در خط فرمان استفاده نمایید: 
 msiexec /i SqlLocalDB.msi /qn IACCEPTSQLLOCALDBLICENSETERMS=YES
همچنین می‌توانید مراحل نصب را توسط فایل نصاب انجام دهید: 


نحوه اتصال به LocalDB توسط Sql Server Management Studio 

اگر net framework. خود را از نسخه 4 به 4.0.2 و یا نسخه‌های بعد از آن به روز رسانی کرده باشید می‌توان توسط Sql Server 2012 Management Studio به Sql server LocalDB وصل شد. عبارت local)\v11.0) را به عنوان نام سرور وارد نمایید.

مجددا لازم به ذکر است که امکان اتصال توسط Management Studio‌های قبلی به بانک LocalDB امکان پذیر نمی‌باشد. 


برای مطالعه بیشتر

مطالب
کاهش حجم لاگ‌ فایل‌های اس‌کیوال سرور 2005 و 2008
نمی‌دونم تابحال به صورت جدی با SharePoint مایکروسافت کار کردید یا نه؟ این برنامه که عمده کارهای خودش رو با SQL server انجام میده در طول یک روز ممکن است تا 80 گیگ log file اس‌کیوال سرور تولید کند و بعد از چند روز اگر به همین صورت به حال خود رها شود (که عموما هم به همین صورت است!) ممکن است دیگر قادر به استفاده از سرور به دلیل پر شدن درایوی که لاگ فایل‌ها در آن ذخیره می‌شوند نباشید.
همچنین رشد tempdb نیز توسط این برنامه بسیار چشم‌گیر است. بنابراین همیشه به‌خاطر داشته باشید محل قرارگیری tempdb و همچنین محل قرارگیری لاگ فایل‌ها (که هر دو قابل تنظیم هستند) را در درایوهایی قرار دهید که حداقل 100 گیگ فضای خالی در آنها موجود باشد.
با استفاده از اسکریپت زیر می‌شود حجم لاگ فایل‌های اس کیوال سرور را به حداقل رساند و نفس راحتی کشید! این مساله اگر جدی گرفته نشود واقعا تبدیل به یک کابوس می‌شود!
اسکریپت زیر کلیه دیتابیس‌های موجود را یافته و shrink می‌کند. قسمت offline و online کردن آن هم به این خاطر است که ارتباط تمام کاربران متصل را به صورت آنی قطع می‌کند (یکی از چندین روش موجود برای kill کردن کاربران است). (یک stored procedure از آن درست کنید و با تعریف یک job جدید در اس کیوال سرور ، این stored procedure را برای مثال هر روز ساعت 3 بامداد به صورت خودکار اجرا کنید)
Declare @database nvarchar(1000)
Declare @tsql nvarchar(4000)
Declare DatabaseCursor Cursor
Local
Static
For
select name from master.dbo.sysdatabases
open DatabaseCursor
fetch next from DatabaseCursor into @database

while @@fetch_status = 0
begin
print 'database:' + @database
if @database not in ('tempdb','master','model','msdb')
begin
SET @tsql = 'use master;
alter database ['+@database+'] set offline with rollback immediate;
alter database ['+@database+'] set online;
DECLARE @dbLogName nvarchar(500) ;
Use ['+@database+'] ;
select @dbLogName = rtrim(ltrim(name)) from sysfiles WHERE FILEID=2;
ALTER DATABASE ['+@database+'] SET SINGLE_USER ;
DBCC SHRINKFILE(@dbLogName , 2) ;
BACKUP LOG ['+@database+'] WITH TRUNCATE_ONLY ;
DBCC SHRINKFILE(@dbLogName , 2) ;
ALTER DATABASE ['+@database+'] SET MULTI_USER ;'
exec(@tsql)
end
fetch next from DatabaseCursor into @database
end

close DatabaseCursor

deallocate DatabaseCursor
اسکریپت فوق با SQL Server 2005 سازگار است اما در SQL Server 2008 منسوخ شده است! (قسمت truncate کردن)
نسخه سازگار با SQL server 2008 آن به صورت زیر است:

Declare @database nvarchar(1000)
Declare @tsql nvarchar(4000)
Declare DatabaseCursor Cursor
Local
Static
For
select name from master.dbo.sysdatabases
open DatabaseCursor
fetch next from DatabaseCursor into @database

while @@fetch_status = 0
begin
print 'database:' + @database
if @database not in ('tempdb','master','model','msdb')
begin
SET @tsql = 'use master;
alter database ['+@database+'] set offline with rollback immediate;
alter database ['+@database+'] set online;
DECLARE @dbLogName nvarchar(500) ;
Use ['+@database+'] ;
select @dbLogName = rtrim(ltrim(name)) from sysfiles WHERE FILEID=2;
ALTER DATABASE ['+@database+'] SET RECOVERY SIMPLE;
ALTER DATABASE ['+@database+'] SET SINGLE_USER ;
DBCC SHRINKFILE(@dbLogName , 2) ;
ALTER DATABASE ['+@database+'] SET MULTI_USER ;
ALTER DATABASE ['+@database+'] SET RECOVERY FULL;'
exec(@tsql)
end
fetch next from DatabaseCursor into @database
end

close DatabaseCursor

deallocate DatabaseCursor
ماخذ اصلی مورد استفاده:
http://go.microsoft.com/fwlink/?LinkId=111531&clcid=0x409


نظرات مطالب
بررسی خطاهای ممکن در حین راه اندازی اولیه برنامه‌های ASP.NET Core در IIS
حداقل دو دلیل را می‌تواند داشته باشد:
- کاربر application pool برنامه (و یا کاربری که توسط آن به بانک اطلاعاتی متصل می‌شوید)، دسترسی مناسبی را به SQL Server ندارد. در قسمت مدیریت کاربران SQL Server، این کاربر باید حداقل دسترسی‌های db_datareader و db_dataweriter را بر روی دیتابیس شما داشته باشد.
- کوئری‌های شما بر اساس اسکیمای dbo صادر می‌شوند، اما اسکیمای واقعی بانک اطلاعاتی موجود در هاست، برای کاربر شما مثلا user1 است و نه dbo مدیریتی. در این حالت نمی‌توانید کوئری‌هایی مانند select * from dbo.table1 را صادر کنید. باید کوئری‌های شما با اسکیمای جدید select * from user1.table1 اجرا شوند.
این موارد در نظرات سری EF Code First بررسی شده‌اند و در اینجا هم تفاوتی نمی‌کنند؛ چون موارد پایه‌ای مدیریت دسترسی‌های SQL Server هستند.
مطالب دوره‌ها
نگاهی به محتوا و نحوه‌ی تشکیل ایندکس‌های FTS
SQL Server به همراه تعدادی تابع سیستمی است که امکان مشاهده‌ی ریز جزئیات تشکیل دهنده‌ی ایندکس‌های FTS را فراهم می‌کنند. در ادامه قصد داریم این موارد را بررسی کنیم.

متد sys.dm_fts_index_keywords

این متد محتوای full-text index یک جدول را باز می‌گرداند. از آن می‌توان برای موارد ذیل استفاده کرد:
- آیا واژه کلیدی خاصی جزو full-text index است؟
- چه تعداد رکورد دارای واژه‌ی کلیدی خاصی هستند؟
- متداولترین واژه‌های کلیدی موجود در ایندکس کدامند؟
- کدام واژه را می‌توان به عنوان stop word تشخیص داد؟ شاید پس از بررسی، تشخیص داده شود که بهتر است متداولترین واژه‌ی کلیدی ایندکس شده، به stop list اضافه شود.

 SELECT *
FROM sys.dm_fts_index_keywords(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.Documents'));



متد sys.dm_fts_index_keywords_by_document

این متد اطلاعاتی را در سطح اسناد باز می‌گرداند. کاربردهای آن می‌توانند شامل موارد زیر باشند:
- یافتن جمع تعداد واژه‌های کلیدی که یک full-text index دارا است.
- آیا واژه‌ی کلیدی مورد نظر، در ردیف در حال بررسی وجود دارد؟
- یک واژه‌ی کلیدی چندبار در کل ایندکس ظاهر شده‌است؟
- یک واژه‌ی کلیدی در یک ردیف یا سند مشخص، چندبار تکرار شده‌است؟
- یک ردیف یا سند، از چند واژه‌ی کلیدی تشکیل شده‌است؟

 SELECT
 I.document_id,
 D.title,
 I.display_term,
 I.occurrence_count
FROM sys.dm_fts_index_keywords_by_document(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.Documents')) AS I
INNER JOIN dbo.Documents D
ON D.id = I.document_id;



متد sys.dm_fts_index_keywords_by_property

در قسمت‌های قبل، خواص و متادیتای اسناد آفیس را نیز ایندکس کردیم. این متد، اطلاعات مرتبط با خواص اسناد موجود در full-text index را باز می‌گرداند.
کاربردهای آن:
- چه محتوایی، در خاصیتی مشخص از سندی معلوم، ذخیره شده‌است؟
- خاصیت مورد نظر چه اندازه بکار رفته و تکرار شده‌است؟
- چه اسنادی دارای خاصیتی مشخص هستند؟

 SELECT
 I.document_id,
 D.title,
 I.display_term,
 I.property_id
FROM sys.dm_fts_index_keywords_by_property(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.Documents')) AS I
INNER JOIN dbo.Documents D
ON D.id = I.document_id;



متد sys.dm_fts_parser

متدهای قبلی که بررسی کردیم، نیاز به یک جدول و وجود full-text index بر روی آن دارند؛ اما متد dm_fts_parser خیر. این متد یک ورودی را گرفته و سپس تمام مراحل تهیه‌ی یک full-text index را به صورت پویا انجام می‌دهد.
کاربردهای آن:
- درک اینکه موتور FTS با یک ورودی رشته‌ای چگونه رفتار می‌کند.
- استخراج ایندکس‌های یک متن و ذخیره‌ی دستی آن در یک جدول.
- استخراج واژه‌های کلیدی یک رشته.
- آنالیز پویای INFLECTIONAL (مانند مثال زیر)
 SELECT
 display_term,
 keyword
FROM sys.dm_fts_parser(N'"Mycustom string"', 1033, NULL, 0);


 SELECT *
FROM sys.dm_fts_parser('FORMSOF(INFLECTIONAL,'+ 'term' + ')', 1033, NULL, 0);


در اینجا پارامتر دوم آن شماره زبان مورد استفاده است. پارامتر سوم مشخص کننده‌ی stop list می‌تواند باشد و پارامتر سوم حساسیت به لهجه را مشخص می‌کند.
نظرات مطالب
ساخت DropDownList های مرتبط به کمک jQuery Ajax در MVC
مشکلم حل شد. 
متد اجرا می‌شد. ولی در قسمت کنترلر حالت چرخشی پیش می‌اومد که نمی‌تونه به json تبدیل بشه. با new حل شد.
var Cities =from c in Cities
Select new {Id=c.Id, Name=c.Name}; 
return Json(Cities  , JsonRequestBehavior.AllowGet); 
نظرات مطالب
اعمال صفحه بندی به کمک OFFSET و FETCH در SQL Server 2012
سلام  
دوست عزیز، مثالی که برای شما زده شد، امکان سورت دلخواه را فراهم می‌کند، شما می‌توانید، هر کدام را به دلخواه نزولی یا صعودی نمایید، محدودیتی ندارد، برای مطالعه بیشتر می‌توانید به آدرس زیر مراجعه نمایید:
یادآور شوم،چنانچه Performance برای شما اهمیت دارد، بهتر است از Case در Order by استفاده ننمایید، و بهتر است در زمان Run Time از طریق کد نویسی سمت سرور، Script خود را Generate نمایید، به عنوان مثال
SELECT BusinessEntityID, FirstName, LastName
FROM Testoffset
ORDER BY BusinessEntityID Desc,Firstname ASC
OFFSET 3 ROWS
FETCH First 3 ROWS only
موفق باشید.