ایندکس در SQL Server و تأثیر آن بر بهینه‌سازی کوئری‌ها

ایندکس در SQL Server و تأثیر آن بر بهینه‌سازی کوئری‌ها

نوشته شده توسط: مهدی شیشه بری
تاریخ انتشار: ۲۸ مرداد ۱۳۹۶
آخرین بروزرسانی: 13 اسفند 1403
زمان مطالعه: 9 دقیقه
۴.۷
(۱۲)

ایندکس در SQL Server، شاید خواندن چنین جمله‌ای برای‌تان عجیب باشد؛ ” بسیاری از توسعه‌دهندگان نرم‌افزارهای کاربردی و یا مدیران دیتابیس‌ها اهمیتی چندانی به مقوله ایندکس‌ها نمی‌دهند! ” برخی از آنها صرفا ایجاد محدودیت‌های Primary Key و Unique Key را برای جداول کافی می‌دانند و برخی دیگر حتی نسبت به چنین موضوعی آگاهی نداشته و تنها از روی عادت همیشگی، چنین محدودیت‌هایی را اِعمال می‌کنند. بعید می‌دانم مخاطب این مجموعه مقالات، چنین افرادی باشند.

گروه دیگری هم هستند که نسبت به موضوع ایندکس‌گذاری و نقش آن در افزایش عملکرد کوئری‌ها بسیار حساس هستند اما آیا واقعا به اعتبار ایجاد ایندکس‌های مناسب بر روی جداول، می‌توان ادعا داشت که بر تمامی مشکلات غلبه شده و به‌نهایت کارآیی در دیتابیس رسیده‌ایم؟
شما در این مجموعه مقالات درخواهید یافت که ایندکس‌گذاری مناسب فقط بخشی از مسیر بهینه‌سازی و افزایش کارآیی است چرا که غفلت از درست‌ نویسی کوئری و عدم رعایت استاندارها می‌تواند موجب تاثیر منفی عملکرد ایندکس‌ها شود.
نکته مهم: تمامی کوئری‌های این مجموعه مقالات، بر روی دیتابیس AdventureWorks2016 و در محیط نرم افزار SSMS 2016 و ۲۰۱۷ اجرا شده است.

دوره کوئری نویسی نیک آموز

 عملگر LIKE

همان‌ طور که می‌دانید با استفاده از عملگر LIKE می‌توان بر روی مقادیر فیلدهای موجود در جداول، عملیات جستجو را بر اساس کاراکترها و یا الگوهای موردنظر انجام داد. فرض کنید از جدول Address به دنبال اطلاعات مشتریانی هستیم که یکی از نشانی‌های آنها که در فیلد AddressLine1 ذخیره شده است، با کاراکتر a آغاز شده باشد. در این حالت عملگر LIKE نهایت استفاده را از ایندکس‌های احتمالیِ موجود بر روی این فیلد خواهد برد.

USE AdventureWorks2016
GO
SET STATISTICS IO ON;
SELECT
AddressID, AddressLine1, AddressLine2, City, StateProvinceID, PostalCode
FROM Person.Address
WHERE AddressLine1 LIKE 'a%';

ایندکس در SQL Server شما با اجرای کوئری بالا و مراجعه به آمار و اطلاعات I/O از بخش Messages خواهید دید. که کم‌ترین تعداد Page برای بازیابی چنین رکوردهایی مورد بررسی قرار گرفته شده است. هم‌چنین با مشاهده Plan اجرایی آن نیز خواهید دید که از عملیات Index Seek استفاده شده است. در این مثال عملگر LIKE به‌خوبی از قابلیت‌های ایندکس‌ها استفاده کرده است.
 عملیات Index Seekعملیات Index Seek

اما چالش اساسی از زمانی آغاز خواهد شد که به دنبال مقادیری باشیم که کاراکترها یا الگوی مورد ارزیابی به‌عنوان بخشی از مقادیر فیلدها باشد؛ به‌عبارت دیگر آن‌ها در ابتدای مقادیر فیلدها قرار نگرفته باشند. در این حالت دیگر مزیت مرتب‌سازی توسط ایندکس‌ها چندان اهمیتی نخواهد داشت و Engine مربوط به SQL Server نمی‌تواند از این قابلیت استفاده کند چرا که در این‌جا مرتب‌سازی بر اساس چپ‌ترین کاراکترِ مقادیر موجود در فیلدها انجام شده است. (توجه داشته باشید که در این‌جا نوع‌داده‌ی فیلد مورد‌نظر برابر با VARCHAR می‌باشد.)
به عنوان مثال در کوئری زیر به‌دنبال رکوردهایی هستیم که مقدار فیلد AddressLine1 آن حاوی عبارت Longbrook باشد.

SELECT
AddressID, AddressLine1, AddressLine2, City, StateProvinceID, PostalCode
FROM Person.Address
WHERE AddressLine1 LIKE '%Longbrook%';

پس از اجرای کوئری بالا و با مراجعه به آمار و اطلاعات I/O از بخش Messages خواهید دید که برای بازیابی چنین رکوردهایی تعداد Page های خوانده شده نسبت به حالت قبل به‌شدت افزایش پیدا کرده است. هم‌چنین با مشاهده Plan اجرایی آن نیز خواهید دید که دیگر خبری از عملیات Index Seek نیست و SQL Server برای بازیابی رکوردها مجبور شده است تا رکوردهای جدول را Scan کند.
عملیات Index Seekعملیات Index Seek

توجه داشته باشید که این دو مثال بر روی جدولی اجرا شده که شامل بیست هزار رکورد است. در این حالت اختلاف میان عملیات‌های Index Seek و Index Scan چندان محسوس نخواهد بود اما در دیتابیس‌های بزرگ و با تعداد کاربران زیاد، نوشتن چنین کوئری‌هایی می‌تواند زمینه‌های بروز Locking و Blocking را فراهم کند. حال می‌خواهم راه‌کارهای مختلف برای رفع چنین مشکلی را برایتان تشریح کنم.


مشاهده کامل‌ترین و بروزترین آموزش sql server در نیک آموز


راه‌حل اول

در سازمان یا شرکت‌مان یک قانون سفت و سخت وضع کنیم که هیچ‌کس حق ندارد به این شکل از عملگر LIKE استفاده کند وگرنه جریمه خواهد شد! به‌نظر من، این قانون بیشتر از طرف مدیران کم‌تجربه یا کم‌دانش ارائه خواهد شد؛ پس اصلا منصفانه نیست.

راه‌حل دوم

به‌جای اِعمال رفتارهای غیر‌مدیریتی بهتر است یادی کنیم از مرحوم سهراب سپهری: ” چشم ها را باید شست، جور دیگر باید دید! “
برای رفع چنین مشکلی می‌توان از FULLTEXT INDEX ها استفاده کرد هر چند که بسیاری از افراد به‌دلیل عدم آشنایی، از چنین قابلیت‌هایی استفاده نمی‌کنند. با استفاده از FULLTEXT INDEX کلمات، درون یک یا چند فیلد به‌همراه موقعیت‌شان در جدول، فهرست‌بندی می‌شوند که همین موضوع در هنگام اجرای کوئری موجب افزایش سرعت شده و دیگر نیازی به پیمایش تمامی رکوردها نخواهد بود. برای این کار می‌بایست ابتدا یک FULLTEXT CATALOG تعریف کنیم:

CREATE FULLTEXT CATALOG IndexKiller AS DEFAULT;

سپس FULLTEXT INDEX ای را بر روی فیلد موردنظر تعریف می‌کنیم:

CREATE FULLTEXT INDEX ON Person.Address(AddressLine1)
KEY INDEX PK_Address_AddressID;
GO

در نهایت تغییراتی کوچکی را بر روی کوئری انجام می‌دهیم. در این‌جا می‌بایست در بخش WHERE یکی از توابع مربوط به FULLTEXT INDEX را با عنوان CONTAINS مورد استفاده قرار دهیم.

SELECT
AddressID, AddressLine1, AddressLine2, City, StateProvinceID, PostalCode
FROM Person.Address
WHERE CONTAINS (AddressLine1,'Longbrook');

پس از اجرای کوئری و مشاهده آمار و اطلاعات I/O خواهید دید که خوانش تعداد Page ها به‌ مقدار قابل توجهی کاهش یافته است. هم‌چنین با مراجعه به Plan اجرایی کوئری بالا می‌بینید که از عملیات Index Seek استفاده شده است.
تعداد Page ها به‌مقدار قابل توجهی کاهش یافته است.تعداد Page ها به‌مقدار قابل توجهی کاهش یافته است.

مجددا این بار هر دو کوئری را با هم اجرا می‌کنیم. کوئری اول با استفاده از عملگر LIKE و کوئری دوم با استفاده از قابلیت FULLTEXT Index عملیات جستجو را انجام خواهند داد. افراد علاقه‌مند می‌توانند با مطالعه مقاله پرکاربردترین دستورات SQL Server، دانش خود را در زمینه کوئری‌نویسی گسترش دهند.

-- Query with LIKE operator
SELECT
AddressID, AddressLine1, AddressLine2,
City, StateProvinceID, PostalCode
FROM Person.Address
WHERE
AddressLine1 LIKE '%Longbrook%';
-- Query with LIKE operator
SELECT
AddressID, AddressLine1, AddressLine2,
City, StateProvinceID, PostalCode
FROM Person.Address
WHERE
CONTAINS (AddressLine1,'Longbrook');

در تصویر زیر مقایسه آمار و اطلاعات I/O و میزان Cost مربوط به Plan اجرایی هر دو کوئری نمایش داده شده است و شما می‌بینید که چگونه با استفاده از قابلیت FULLTEXT INDEX زمینه‌های افزایش عملکرد اجرایی کوئری و کاهش استفاده از منابع را فراهم کرده‌ایم.

زمینه‌های افزایش عملکرد اجرایی کوئری و کاهش استفاده از منابعزمینه‌های افزایش عملکرد اجرایی کوئری و کاهش استفاده از منابع

در قسمت‌ قبلی ایندکس در SQL Server دیدید که چگونه با استفاده‌ی نامناسب از عملگر LIKE در بخش WHERE، زمینه‌های عدم استفاده از تاثیر مثبت ایندکس‌ها در افزایش کارآیی عملکرد کوئری‌ها فراهم می‌شود. در این قسمت می‌خواهم شما را با یکی دیگر از سناریو‌هایی که موجب خنثی شدن قابلیت ایندکس‌ها می‌شود، آشنا کنم.

 عملیات Concatenation

در بسیاری از موارد شاید برای‌تان پیش آمده باشد که بخواهید در بخش WHERE از کوئری‌تان مقادیر مختلفی را با یکدیگر پیوند داده و جستجو را بر اساس آنها انجام دهید؛ در حقیقت با این کار شما می‌خواهید از عملیات Concatenation استفاده کنید.
فرض کنید در جدول Person از دیتابیس AdventureWorks2016 می‌خواهید عملیات جستجو برای فردی با مشخصات Gustavo Achong را انجام دهید. برای نوشتن چنین کوئری‌ای می‌بایست در بخش WHERE، فیلدهای FirstName و LastName را به‌همراه یک کاراکتر فضای خالی با یکدیگر پیوند داد

USE AdventureWorks2016
GO
SET STATISTICS IO ON;
SELECT
BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE FirstName + ' ' + LastName = 'Gustavo Achong';

اگر به Plan اجرایی این کوئری نگاهی بیاندازید متوجه می‌شوید که عملیات Index Seek انجام نشده است و برای واکشی همین یک رکورد، تمامی رکوردهای جدول Person خوانده شده است!

رکوردهای جدول Person

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

CREATE INDEX IX_PersonContact_FirstNameLastName ON Person.Person (FirstName, LastName)
GO
[/sql]
مجددا کوئری زیر را اجرا می‌کنیم.
[sql]
SELECT
BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE FirstName + ' ' + LastName = 'Gustavo Achong';

انتظارمان این بود که پس از اجرای کوئری، ایندکس تعریف‌شده بر روی این دو فیلد موجب افزایش کارآیی عملکرد کوئری شود اما با نگاهی به آمار و اطلاعات I/O از بخش Messages و Plan اجرایی کوئری متوجه خواهیم شد که چنین امری تحقق نیافته است!
 نگاهی به آمار و اطلاعات I/O از بخش Messages و Plan اجرایی کوئرینگاهی به آمار و اطلاعات I/O از بخش Messages و Plan اجرایی کوئری

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

SELECT
BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE FirstName + LastName = 'GustavoAchong';

علیرغم انتظارمان باز هم تعداد Page های خوانده شده برابر با ۹۹ خواهد بود و در Plan اجرایی کوئری نیز خبری از عملیات Index Seek نیست؛ به‌عبارت دیگر عملکرد این دو کوئری با یکدیگر یکسان خواهد بود.
اگر فکر می‌کنید راه‌کار مناسب، استفاده از تابع CONCAT است باید به شما بگویم که سخت در اشتباه هستید. اگر دو کوئری زیر را با یکدیگر اجرا کنید خواهید دید که به لحاظ تعداد Page های خوانده‌شده، وضعیت مشابهی دارند اما Plan اجرایی کوئری‌ای که در آن از تابع CONCAT استفاده شده است دارای Cost بالاتری است! این معضل در قسمت بعدی این مجموعه مقالات مورد بررسی قرار خواهد گرفت.

SELECT
BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE FirstName + LastName = 'GustavoAchong';
SELECT
BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE CONCAT(FirstName , LastName) = 'GustavoAchong'.

Plan اجرایی کوئری‌ای که در آن از تابع CONCAT استفاده شده استPlan اجرایی کوئری‌ای که در آن از تابع CONCAT استفاده شده است

به‌ نظر می‌رسد که باید در این‌‌جا از عملیات پیوندِ میان فیلدها صرف‌نظر کرده و به‌دنبال راه‌کار مناسبی باشیم تا از قابلیت‌های ایندکسِ موجود بر روی این دو فیلد نهایت استفاده را برده باشیم. در کوئری زیر به‌جای استفاده از عملگرهای + و یا تابع CONCAT از عملگر منطقی AND استفاده خواهیم کرد. یشنهاد میکنیم برای درک بهتر مفاهیم کوئری نویسی را مطالعه کنید.

SELECT SELECT  BusinessEntityID, FirstName,LastName
FROM Person.Person WHERE FirstName + LastName = 'GustavoAchong';
SELECT  BusinessEntityID, FirstName,LastName
FROM Person.Person WHERE FirstName = 'Gustavo' AND LastName = 'Achong';

پس از اجرای کوئری خواهید دید که نوشتن درستِ یک کوئری چگونه زمینه‌های افزایش کارآیی و استفاده‌ی بهینه از قابلیت‌های ایندکس‌ها را فراهم خواهد کرد.
 قابلیت‌های ایندکس‌هاقابلیت‌های ایندکس‌ها

اجرای همزمان دو کوئری زیر و مقایسه نتایج آمار و اطلاعات I/O و Cost هر یک از آنها نیز خالی از لطف نیست.

SELECT BusinessEntityID, FirstName, LastNameFROM Person.Person
WHERE FirstName + LastName = 'GustavoAchong';
SELECT BusinessEntityID, FirstName, LastNameFROM Person.Person
WHERE FirstName = 'Gustavo' AND LastName = 'Achong'; >

 

در قسمت‌های قبلی ایندکس در SQL Server دیدید، که چگونه با استفاده‌ی نامناسب از عملگر LIKE و عملیات Concatenation، زمینه‌های عدم استفاده از تاثیر مثبت ایندکس‌ها در افزایش کارآیی عملکرد کوئری‌ها فراهم می‌شود. در قسمت سوم این مقاله می‌خواهم شما را با یکی دیگر از سناریو‌هایی که موجب خنثی شدن قابلیت ایندکس‌ها می‌شود، آشنا کنم.

 ستون‌های محاسباتی (Computed Columns)

همان‌طور که می‌دانید در برخی از موارد مقادیر یک یا چندین ستون از جدولی به‌صورت عبارت یا Expression تعریف می‌شوند. چنین مقادیری ممکن است، در حین اجرای یک کوئری و برای جلوگیری از محاسباتِ زمانِ اجرا مورد استفاده قرار گیرند. از طرفی چنین ستون‌هایی می‌توانند با ستون‌های دیگری وابستگی داشته باشند تا به‌محض هرگونه تغییری در سایر ستون‌ها، تغییرات بر روی آنها نیز اِعمال شود. به چنین ستون‌هایی Computed Columns گفته می‌شود. زمانی که شما مجبور هستید تا نتیجه اجرای یک تابع یا محاسبات مبتنی بر چندین ستون را در جدول‌تان نگهداری کنید، استفاده از ستون‌های محاسباتی می‌تواند برای شما مفید واقع شود.
همواره به این نکته مهم توجه داشته باشید، که قابلیت استفاده از ایندکس‌های موجود بر روی ستون‌هایی که بر اساس آنها ستون‌های محاسباتی شکل گرفته است. امکان پذیر نخواهد بود! برای بررسی این موضوع، ابتدا دو ستون محاسباتی جدید را برای جدول Person درنظر می‌گیریم. اولین ستون محاسباتی شامل ترکیبی از فیلدهای نام و نام‌خانوادگی است اما دومین ستون محاسباتی معنای خاصی نداشته و صرفا جهت بررسی یک سناریو تعریف می‌شود. افراد علاقه‌مند می‌توانند با مطالعه مقاله پرکاربردترین دستورات SQL Server، دانش خود را در زمینه کوئری‌نویسی گسترش دهند.

USE AdventureWorks2016
GO
ALTER TABLE Person.Person
ADD FirstLastName AS (FirstName + ' ' + LastName)
,CalculateValue AS (BusinessEntityID * EmailPromotion);

اکنون کوئری‌های زیر را اجرا می‌کنیم.

SET STATISTICS IO ON
SELECT
BusinessEntityID, FirstName, LastName, FirstLastName
FROM Person.Person
WHERE FirstLastName = 'Gustavo Achong';
SELECT
BusinessEntityID, CalculateValue
FROM Person.Person
WHERE CalculateValue = 198;

با مراجعه به Plan اجرایی این کوئری‌ها خواهیم دید، که جهت بازیابی رکوردها از عملیات Scan استفاده شده است. در قسمت‌های قبلی این مجموعه مقالات به شما تذکر دادیم که این عملیات با افزایش حجم دیتابیس، رکوردهای جدول و تعداد کاربران همزمان می‌تواند احتمال بروز پدیده Blocking و استفاده از I/O های بیشتر برای درخواست‌ها را فراهم کند. این موضوع در بخش آمار و اطلاعات I/O نیز قابل مشاهده است که چگونه برای بازیابی نتایج موردنظر، تمامی رکوردها مورد ارزیابی قرار گرفته شده است.
حتمال بروز پدیده Blocking و استفاده از I/O های بیشترحتمال بروز پدیده Blocking و استفاده از I/O های بیشترحتمال بروز پدیده Blocking و استفاده از I/O های بیشتر

با توجه به عدم استفاده از ایندکس ستون‌های مبداء در ستون‌های محاسباتی، اکنون برای این دو ستونِ جدید ایندکس‌هایی از نوع NONCLUSTERED تعریف می‌کنیم.

CREATE INDEX IX_PersonPerson_FirstLastName
ON Person.Person(FirstLastName);
CREATE INDEX IX_PersonPerson_CalculateValue
ON Person.Person(CalculateValue);

با اجرای مجدد کوئری‌ها خواهیم دید که بازیابی رکوردها از طریق عملیات Index Seek انجام شده است. مقایسه آمار و اطلاعات I/O نیز نشان از کاهش چشمگیر تعداد Page های خوانده‌شده در این عملیات خواهد داشت.
کاهش چشمگیر تعداد Page های خوانده‌شدهکاهش چشمگیر تعداد Page های خوانده‌شدهکاهش چشمگیر تعداد Page های خوانده‌شده
کاهش چشمگیر تعداد Page های خوانده‌شده

در قسمت‌های قبلی ایندکس در SQL Server دیدید که چگونه با نوشتن یک کوئری نامناسب در هنگام جستجوی مقادیر مختلف از جداول، ناخواسته زمینه‌های لازم برای عدم استفاده از ایندکس‌های موجود را فراهیم می‌کنیم!

دوره کوئری نویسی نیک آموز

توابع تک مقدار یا اسکالر (Scalar Functions)

 

در این قسمت می‌خواهیم درخصوص عوارض استفاده از توابع تک‌مقدار یا Scalar Functionها در هنگام نوشتن کوئری‌ها و در بخش WHERE با شما صحبت کنیم! همان‌طور که می‌دانید مایکروسافت توابع مختلفی را به‌شکل Built-in در SQL Server ارائه کرده است. این توابع در قالب دسته‌‎‌بندی‌های مختلفی، قابلیت کار با انواع‌داده از قبیل رشته‌ها، اعداد، تاریخ، زمان و … را فراهم می‌کنند. ما می‌توانیم با استفاده از این‌گونه توابع علاوه‌بر صرفه‌جویی در زمان، به افزایش کارآیی کوئری‌ها نیز کمک شایانی کرده باشیم. عملکرد این توابع به‌گونه‌ای است که با تغییر در شکل اصلی مقادیر فیلدها، مقادیر مناسب‌تری را برای نوشتن کوئری‌هایِ مختلف فراهم خواهد کرد.
این کار حتی از طریق توابعی که توسط کاربران و با عنوان User Define Function شناخته می‌شود نیز امکان‌پذیر است اما باید توجه داشت که چنین تغییراتی می‌تواند موجب خنثی شدن عملکرد ایندکس‌های موجود بر روی مقادیر فیلدهای جداول شود چرا که استفاده از این‌گونه توابع، شکل اصلی مقادیر فیلدها را دست‌خوش تغییر می‌کند. بدیهی است که این مقادیر، هیچ‌گونه سنخیتی با مقادیر ایندکس‌گذاری شده در حین عملیات ایندکس‌گذاری ندارند. به‌عبارت ساده‌تر هیچ‌گونه آماری از میزان فراوانی آن‌ها در دسترس نبوده تا بر اساس آنها بهینه‌سازِ SQL Server (Query Optimizer) اقدام به ایجاد یک Plan بهینه از آن‌ها داشته باشد.
برای آن‌که تاثیر این‌گونه از توابع را بر روی روند اجرایی کوئری‌ها ببینید به اسکریپت‌های زیر توجه کنید:

USE AdventureWorks2014
GO
SET STATISTICS IO ON
-- Query 1
SELECT
BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE FirstName = 'Gustavo';
GO
-- Query 2
SELECT
BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE RTRIM(FirstName) = 'Gustavo';
GO

هر دو کوئری بالا قرار است اطلاعات مربوط به رکوردی را نمایش دهند که مقدار فیلد FirstName آن برابر با Gustavo است. پس از اجرای همزمان هر دو کوئری و با مراجعه به آمار و اطلاعات I/O خواهید دید، کوئری دوم که در بخش WHERE از تابع RTRIM استفاده کرده است، نسبت به کوئری اول تعداد Page بیشتری را خوانده است!
کوئری دوم نسبت به کوئری اول تعداد Page بیشتری را خوانده است!

این اختلاف بسیار فاحش، در مقایسه‌ی Plan اجرایی و میزان استفاده از منابع نیز به‌وضوح قابل مشاهده است.

مقایسه‌ی Plan اجرایی و میزان استفاده از منابعواقعیت این است که برای رفع این معضل نمی‌توان یک راه‌کار عمومی ارائه کرد. شاید توجه به این جمله کلیدی، چندان دور از واقعیت نباشد: “پیشگیری بهتر از درمان است!” افراد علاقه‌مند می‌توانند با مطالعه مقاله پرکاربردترین دستورات SQL Server، دانش خود را در زمینه کوئری‌نویسی گسترش دهند.
ارائه یک راه‌حل مناسب، کاملا متناسب با پارامترهایی هم‌چون مدل کسب‌و‌کار و قواعد حاکم بر آن، مدل طراحی دیتابیس، ساختار رکوردهای موجود در جداول و … است. به‌ عنوان مثال فرض کنید قرار است تمامی سفارشاتِ مرتبط با سال ۲۰۱۲ و ماه ۱۲ را از جدول SalesOrderHeader در خروجی نمایش دهیم. برای انجام این کار می‌توان به دو روش اقدام کرد. به اسکریپت‌های زیر توجه کنید:

USE AdventureWorks2014
GO
CREATE INDEX IX_SalesSalesOrderHeader_OrderDate ON Sales.SalesOrderHeader(OrderDate);
GO
SET STATISTICS IO ON;
-- Query 1
SELECT
SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
WHERE MONTH(OrderDate) = 12
AND YEAR(OrderDate) = 2012;
GO
-- Query 2
SELECT
SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
WHERE OrderDate BETWEEN '20121201' AND '20121231';
GO

از آنجا که بر روی فیلد OrderDate ایندکسی مناسبی وجود ندارد، ابتدا بر روی آن ایندکسی از نوع Non-Clustered ایجاد می‌کنیم. در ادامه خواهید دید که در اولین کوئری از توابع YEAR و MONTH برای استخراج مقادیر سال و ماه استفاده شده است اما در کوئری دوم صرفا با استفاده از عملگر BETWEEN و تعیین یک بازه زمانی، این کار انجام شده است.
پس از اجرای همزمان هر دو کوئری و مراجعه به آمار و اطلاعات I/O و Plan اجرایی خواهید دید که عدم استفاده از دو تابع YEAR و MONTH تا چه حدی می‌تواند به افزایش عملکرد کوئری و استفاده کمتر از منابع، کمک کند.
عدم استفاده از دو تابع YEAR و MONTH
نتیجه عدم استفاده از دو تابع YEAR و MONTH

سخن پایانی

ایندکس در SQL Server، بنابراین همواره این نکته را به‌خاطر داشته باشید که هنگام استفاده از Scalar Function ها در بخش WHERE اگر تحت هر شرایطی مقادیر ستون‌ها توسط توابع دست‌خوش تغییرات شوند آنگاه به‌احتمال بسیار زیاد، ایندکس‌های موجود بر روی ستون‌ها در هنگام اجرای کوئری، توسط بهینه‌ ساز مورد استفاده قرار نخواهند گرفت. ما در نیک آموز منتظر نظرات ارزشمند شما درباره این مقاله هستیم.

چه رتبه ای می‌دهید؟

میانگین ۴.۷ / ۵. از مجموع ۱۲

اولین نفر باش

title sign
دانلود مقاله
ایندکس در SQL Server و تأثیر آن بر بهینه‌سازی کوئری‌ها
فرمت PDF
7 صفحه
حجم 1 مگابایت
دانلود مقاله
جشواره عیدانه نیک آموز
title sign
معرفی نویسنده
title sign
معرفی محصول
title sign
دیدگاه کاربران

    • چطور میشه در دیتابیس های حجیم پیشرفت این مدل ایندکس رو دید ؟ بهردرصد منظورمه چون ایندکس fulltext بسیار زمان بره

    • عالی بود استاد، ممنون

    • با سلام و خسته نباشید خدمت جناب آقای مهندس مهدی شیشه بری
      از بابت این مقاله بسیار مفید و عالی بسیار ممنونم این مقاله مقاله ای هست که برای هر کسی که می خواهد sql server را حتی به صورت خیلی متوسط هم یاد بگیر خیلی مفید هست چون خیلی به درد بخور هست از شما ممنونم
      با تشکر از شما

    • با سلام و خسته نباشید خدمت جناب آقای مهندس مهدی شیشه بری
      از بابت این مقاله بسیار مفید و عالی بسیار ممنونم این مقاله مقاله ای هست که برای هر کسی که می خواهد sql server را حتی به صورت خیلی متوسط هم یاد بگیر خیلی مفید هست چون خیلی به درد بخور هست از شما ممنونم
      با تشکر از شما

    • خیلی ممنون. یک پیشنهاد دارم. زیر هر مقاله یک دکمه تشکر باشه که برای همین به کار بره و فضای کامنت برای تشکر پر نکنیم.

    • بسیار کاربردی، سپاس از شما.

    • خوانش این یکی مقاله را هم از دست ندهید:
      https://goo.gl/iznSVu

    • خوانش این یکی مقاله را هم از دست ندهید:
      https://goo.gl/iznSVu

    • عالی بود.
      فقط فکز میکنم تصویر دوم (مربوط به کوئری LIKE ‘%Longbrook%’;) اشتباه گذاشته شده، و عکس مربوط به کوئری فول-تکست هم همان است.
      (آدرس هر دو https://nikamooz.com/wp-content/uploads/2017/08/kill_index_3-e1503163450575.jpg است)

  • 1
  • 2

دانلود رایگان: آموزش SQL Server

هر روز یک ویدئو آموزشی رایگان برای شما ایمیل خواهد شد!

پاپ آپ | SQL Server

  • این قسمت برای اهداف اعتبارسنجی است و باید بدون تغییر باقی بماند.