You are on page 1of 5

‫قاتلین ایندکس ها در ‪[ SQL Server‬بخش چهارم]‬

‫شماره مقاله‪29290 :‬‬

‫عنوان مقاله‪ :‬قاتلین ایندکسها در ‪[ SQL Server‬بخش چهارم]‬


‫نویسنده مقاله‪ :‬مهدی شیشه بری‬
‫تاریخ انتشار‪ :‬مهر ‪1396‬‬
‫منبع‪http://nikamooz.com/kill-indexing-sql-server-part4/ :‬‬

‫مقدمه‬

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

‫نکته مهم‪ :‬تمامی کوئریهای این مجموعه مقاالت‪ ،‬بر روی دیتابیس ‪ AdventureWorks2016‬و در محیط ‪SQL‬‬
‫‪Server Management Studio 2016‬و ‪ 2017‬اجرا شده است‪.‬‬

‫قاتل شماره ‪ – 4‬توابع تک مقدار یا اسکالر )‪(Scalar Functions‬‬

‫در این قسمت میخواهم درخصوص عوارض استفاده از توابع تکمقدار یا ‪Scalar Function‬ها در هنگام نوشتن‬
‫کوئریها و در بخش ‪ WHERE‬با شما صحبت کنم!‬

‫همانطور که میدانید مایکروسافت توابع مختلفی را بهشکل ‪ Built-in‬در ‪ SQL Server‬ارائه کرده است‪ .‬این‬
‫توابع در قالب دستهبندیهای مختلفی‪ ،‬قابلیت کار با انواعداده از قبیل رشتهها‪ ،‬اعداد‪ ،‬تاریخ‪ ،‬زمان و ‪ ...‬را فراهم‬
‫میکنند‪ .‬ما میتوانیم با استفاده از اینگونه توابع عالوهبر صرفهجویی در زمان‪ ،‬به افزایش کارآیی کوئریها نیز‬
‫کمک شایانی کرده باشیم‪ .‬عملکرد این توابع بهگونهای است که با تغییر در شکل اصلی مقادیر فیلدها‪ ،‬مقادیر‬
‫های مختلف فراهم خواهد کرد‪.‬‬
‫مناسبتری را برای نوشتن کوئری ِ‬

‫این کار حتی از طریق توابعی که توسط کاربران و با عنوان ‪ User Define Function‬شناخته میشود نیز‬
‫امکانپذیر است اما باید توجه داشت که چنین تغییراتی میتواند موجب خنثی شدن عملکرد ایندکسهای‬

‫‪www.nikamooz.com‬‬ ‫صفحه‪1 :‬‬


‫قاتلین ایندکس ها در ‪[ SQL Server‬بخش چهارم]‬

‫شماره مقاله‪29290 :‬‬

‫موجود بر روی مقادیر فیلدهای جداول شود چرا که استفاده از اینگونه توابع‪ ،‬شکل اصلی مقادیر فیلدها را‬
‫دستخوش تغییر میکند‪ .‬بدیهی است که این مقادیر‪ ،‬هیچگونه سنخیتی با مقادیر ایندکسگذاری شده در حین‬
‫عملیات ایندکسگذاری ندارند‪ .‬بهعبارت سادهتر هیچگونه آماری از میزان فراوانی آنها در دسترس نبوده تا بر‬
‫ساز ‪ )Query Optimizer( SQL Server‬اقدام به ایجاد یک ‪ 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‬‬

‫‪www.nikamooz.com‬‬ ‫صفحه‪2 :‬‬


‫قاتلین ایندکس ها در ‪[ SQL Server‬بخش چهارم]‬

‫شماره مقاله‪29290 :‬‬

‫هر دو کوئری باال قرار است اطالعات مربوط به رکوردی را نمایش دهند که مقدار فیلد ‪ FirstName‬آن برابر با‬
‫‪ Gustavo‬است‪.‬‬

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

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

‫واقعیت این است که برای رفع این معضل نمیتوان یک راهکار عمومی ارائه کرد‪ .‬شاید توجه به این جمله کلیدی‪،‬‬
‫چندان دور از واقعیت نباشد‪" :‬پیشگیری بهتر از درمان است!"‬

‫‪www.nikamooz.com‬‬ ‫صفحه‪3 :‬‬


]‫ [بخش چهارم‬SQL Server ‫قاتلین ایندکس ها در‬

29290 :‫شماره مقاله‬

‫ مدل طراحی‬،‫ کامال متناسب با پارامترهایی همچون مدل کسبوکار و قواعد حاکم بر آن‬،‫ارائه یک راهحل مناسب‬
.‫ است‬... ‫ ساختار رکوردهای موجود در جداول و‬،‫دیتابیس‬

‫ را از جدول‬12 ‫ و ماه‬2012 ‫سفارشات مرتبط با سال‬


ِ ‫بهعنوان مثال فرض کنید قرار است تمامی‬
‫ به‬.‫ برای انجام این کار میتوان به دو روش اقدام کرد‬.‫ در خروجی نمایش دهیم‬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

www.nikamooz.com 4 :‫صفحه‬
‫قاتلین ایندکس ها در ‪[ SQL Server‬بخش چهارم]‬

‫شماره مقاله‪29290 :‬‬

‫از آنجا که بر روی فیلد ‪ OrderDate‬ایندکسی مناسبی وجود ندارد‪ ،‬ابتدا بر روی آن ایندکسی از نوع ‪Non-‬‬
‫‪ Clustered‬ایجاد میکنیم‪ .‬در ادامه خواهید دید که در اولین کوئری از توابع ‪ YEAR‬و ‪ MONTH‬برای استخراج‬
‫مقادیر سال و ماه استفاده شده است اما در کوئری دوم صرفا با استفاده از عملگر ‪ BETWEEN‬و تعیین یک بازه‬
‫زمانی‪ ،‬این کار انجام شده است‪.‬‬

‫پس از اجرای همزمان هر دو کوئری و مراجعه به آمار و اطالعات ‪ I/O‬و ‪ Plan‬اجرایی خواهید دید که عدم‬
‫استفاده از دو تابع ‪ YEAR‬و ‪ MONTH‬تا چه حدی میتواند به افزایش عملکرد کوئری و استفاده کمتر از منابع‪،‬‬
‫کمک کند‪.‬‬

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

‫در قسمت بعد‪ ،‬بخش پایانی این مجموعه مقاالت ارائه خواهد شد‪.‬‬

‫‪www.nikamooz.com‬‬ ‫صفحه‪5 :‬‬

You might also like