اس کیو ال سرور بوسیله ایجاد پلنهای اجرایی کامپایل شده، سعی در بهینه سازی پروسیجرها دارد. هنگامیکه اس کیو ال سرور یک پروسیجر را کامپایل مینماید، به پارامترهای ارسال شده توجه دارد و یک پلن اجرایی را بر اساس پارامترهای ارسالی ایجاد میکند. به فرآیند تماشا یا توجه به پارامترهای ارسالی به پروسیجر، شنود پارامترها گفته میشود. شنود پارامترها میتواند بعضی از اوقات به کاهش کارآیی پلن اجرایی منجر شود؛ مخصوصا زمانیکه پارامترهایی با کاردینالیتی متفاوت، فراخوانی شوند.
شنود پارامتر چیست؟
شنود پارامتر، قابلیتی است که اس کیو ال سرور توسط آن یک پلن مناسب و بهینه اجرایی را برای پروسیجری با پارامترهای ارسالی، در اولین مرتبه اجرا، تولید خواهد کرد. در ادامه هر فراخوانی پروسیجر با پارامترهای مشابه، منجر به استفاده از پلن اجرایی ذخیره شده خواهد شد. شاید در اولین نگاه این استفاده مجدد، مناسب به نظر برسد. ولی در صورتیکه پروسیجر با پارامترهای متفاوتی فراخوانی شود، ممکن است پلن اجرایی تولید شده بر اساس آن پارامترهای اولیه، برای پارامترهای جدید بهینه نباشد.
پلنهای اجرایی بر اساس چیزهایی که از 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;
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';
در فراخوانی اول، اطلاعات در بازه یک سال و در فراخوانی دوم، در بازه چند روز، درخواست شدهاند. همانطور که گفته شد، پلن اجرایی بر اساس فراخوانی اول ایجاد خواهد شد و فراخوانی دوم نیز براساس همین پلن اجرایی ایجاد شده، اجرا میشود.
همانطور که مشاهده میکنید عملیات 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.
// <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
نحوه اتصال به 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 امکان پذیر نمیباشد.
همچنین رشد 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 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
تولید HTML از پرس و جوی های SQL
نگاهی به محتوا و نحوهی تشکیل ایندکسهای 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 میتواند باشد و پارامتر سوم حساسیت به لهجه را مشخص میکند.
var Cities =from c in Cities Select new {Id=c.Id, Name=c.Name}; return Json(Cities , JsonRequestBehavior.AllowGet);
SELECT BusinessEntityID, FirstName, LastName FROM Testoffset ORDER BY BusinessEntityID Desc,Firstname ASC OFFSET 3 ROWS FETCH First 3 ROWS only