Professional Documents
Culture Documents
مقدمه
در قسمتهای اول ،دوم و سوم این مجموعه مقاالت دیدید که چگونه با نوشتن یک کوئری نامناسب در هنگام
جستجوی مقادیر مختلف از جداول ،ناخواسته زمینههای الزم برای عدم استفاده از ایندکسهای موجود را فراهیم
میکنیم!
نکته مهم :تمامی کوئریهای این مجموعه مقاالت ،بر روی دیتابیس AdventureWorks2016و در محیط SQL
Server Management Studio 2016و 2017اجرا شده است.
در این قسمت میخواهم درخصوص عوارض استفاده از توابع تکمقدار یا Scalar Functionها در هنگام نوشتن
کوئریها و در بخش WHEREبا شما صحبت کنم!
همانطور که میدانید مایکروسافت توابع مختلفی را بهشکل Built-inدر SQL Serverارائه کرده است .این
توابع در قالب دستهبندیهای مختلفی ،قابلیت کار با انواعداده از قبیل رشتهها ،اعداد ،تاریخ ،زمان و ...را فراهم
میکنند .ما میتوانیم با استفاده از اینگونه توابع عالوهبر صرفهجویی در زمان ،به افزایش کارآیی کوئریها نیز
کمک شایانی کرده باشیم .عملکرد این توابع بهگونهای است که با تغییر در شکل اصلی مقادیر فیلدها ،مقادیر
های مختلف فراهم خواهد کرد.
مناسبتری را برای نوشتن کوئری ِ
این کار حتی از طریق توابعی که توسط کاربران و با عنوان User Define Functionشناخته میشود نیز
امکانپذیر است اما باید توجه داشت که چنین تغییراتی میتواند موجب خنثی شدن عملکرد ایندکسهای
موجود بر روی مقادیر فیلدهای جداول شود چرا که استفاده از اینگونه توابع ،شکل اصلی مقادیر فیلدها را
دستخوش تغییر میکند .بدیهی است که این مقادیر ،هیچگونه سنخیتی با مقادیر ایندکسگذاری شده در حین
عملیات ایندکسگذاری ندارند .بهعبارت سادهتر هیچگونه آماری از میزان فراوانی آنها در دسترس نبوده تا بر
ساز )Query Optimizer( SQL Serverاقدام به ایجاد یک Planبهینه از آنها داشته باشد.
اساس آنها بهینه ِ
برای آنکه تاثیر اینگونه از توابع را بر روی روند اجرایی کوئریها ببینید به اسکریپتهای زیر توجه کنید:
USE AdventureWorks2014
GO
SET STATISTICS IO ON
هر دو کوئری باال قرار است اطالعات مربوط به رکوردی را نمایش دهند که مقدار فیلد FirstNameآن برابر با
Gustavoاست.
پس از اجرای همزمان هر دو کوئری و با مراجعه به آمار و اطالعات I/Oخواهید دید ،کوئری دوم که در بخش
WHEREاز تابع RTRIMاستفاده کرده است ،نسبت به کوئری اول تعداد Pageبیشتری را خوانده است!
این اختالف بسیار فاحش ،در مقایسهی Planاجرایی و میزان استفاده از منابع نیز بهوضوح قابل مشاهده است.
واقعیت این است که برای رفع این معضل نمیتوان یک راهکار عمومی ارائه کرد .شاید توجه به این جمله کلیدی،
چندان دور از واقعیت نباشد" :پیشگیری بهتر از درمان است!"
مدل طراحی، کامال متناسب با پارامترهایی همچون مدل کسبوکار و قواعد حاکم بر آن،ارائه یک راهحل مناسب
. است... ساختار رکوردهای موجود در جداول و،دیتابیس
USE AdventureWorks2014
GO
CREATE INDEX IX_SalesSalesOrderHeader_OrderDate ON
Sales.SalesOrderHeader(OrderDate);
GO
-- 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بخش چهارم]
از آنجا که بر روی فیلد OrderDateایندکسی مناسبی وجود ندارد ،ابتدا بر روی آن ایندکسی از نوع Non-
Clusteredایجاد میکنیم .در ادامه خواهید دید که در اولین کوئری از توابع YEARو MONTHبرای استخراج
مقادیر سال و ماه استفاده شده است اما در کوئری دوم صرفا با استفاده از عملگر BETWEENو تعیین یک بازه
زمانی ،این کار انجام شده است.
پس از اجرای همزمان هر دو کوئری و مراجعه به آمار و اطالعات I/Oو Planاجرایی خواهید دید که عدم
استفاده از دو تابع YEARو MONTHتا چه حدی میتواند به افزایش عملکرد کوئری و استفاده کمتر از منابع،
کمک کند.
بنابراین همواره این نکته را بهخاطر داشته باشید که هنگام استفاده از Scalar Functionها در بخش WHERE
اگر تحت هر شرایطی مقادیر ستونها توسط توابع دستخوش تغییرات شوند آنگاه بهاحتمال بسیار زیاد،
ایندکسهای موجود بر روی ستونها در هنگام اجرای کوئری ،توسط بهینهساز مورد استفاده قرار نخواهند گرفت.
در قسمت بعد ،بخش پایانی این مجموعه مقاالت ارائه خواهد شد.