قاتلین ایندکس در SQL Server [بخش دوم]

قاتلین ایندکس در SQL Server [بخش دوم]

نوشته شده توسط: مهدی شیشه بری
۰۵ شهریور ۱۳۹۶
زمان مطالعه: 8 دقیقه
۵
(۳)

مقدمه

در قسمت اول دیدید که چگونه با استفاده‌ی نامناسب از عملگر LIKE در بخش WHERE، زمینه‌های عدم استفاده از تاثیر مثبت ایندکس‌ها در افزایش کارآیی عملکرد کوئری‌ها فراهم می‌شود. در این قسمت می‌خواهم شما را با یکی دیگر از سناریو‌هایی که موجب خنثی شدن قابلیت ایندکس‌ها می‌شود، آشنا کنم.
نکته مهم: تمامی کوئری‌های این مجموعه مقالات، بر روی دیتابیس AdventureWorks2016 و در محیط SQL Server Management Studio 2016 و ۲۰۱۷ اجرا شده است.

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

قاتل شماره ۲ عملیات 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 خوانده شده است!
یک برنامه‌نویس یا مدیر دیتابیس که با قابلیت‌های ایندکس‌ها آشنا است، در این‌جا تصمیم خواهد گرفت تا بر روی این دو فیلد، ایندکس مناسبی را تهیه کند. کوئری زیر این کار را انجام داده و یک 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 اجرایی کوئری متوجه خواهیم شد که چنین امری تحقق نیافته است!
 شاید با کمی تامل در کوئری بالا به این نتیجه برسیم که با حذف کاراکتر فضای خالی از پیوند میان فیلدهای FirstName و LastName مشکل برطرف خواهد شد؛ پس کوئری را به شکل زیر اصلاح می‌کنیم.

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';

به‌نظر می‌رسد که باید در این‌‌جا از عملیات پیوندِ میان فیلدها صرف‌نظر کرده و به‌دنبال راه‌کار مناسبی باشیم تا از قابلیت‌های ایندکسِ موجود بر روی این دو فیلد نهایت استفاده را برده باشیم. در کوئری زیر به‌جای استفاده از عملگرهای + و یا تابع 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'; >

 در قسمت بعدی با یکی دیگر از قاتلین ایندکس‌ها آشنا خواهید شد.

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

میانگین ۵ / ۵. از مجموع ۳

اولین نفر باش

title sign
دانلود مقاله
قاتلین ایندکس در SQL Server [بخش دوم]
فرمت PDF
6 صفحه
حجم 1 مگابایت
دانلود مقاله
title sign
معرفی نویسنده
title sign
دیدگاه کاربران

    • سلام و تشکر
      بسیار عالی است.
      مورد مشابهی داشتم، ولی چون در ورودی کاربر، مشخص نیست اسم و فامیل کدام است این روش کاربرد نداشت. آیا راهی هست که روی ترکیب دو فیلد ایندکس گذاشته شود؟
      بیصبرانه منتظر قسمتهای بعدی مقاله هستم.

      • سوال شما کمی گنگ است.
        فکر می‌کنم اگر ورودی‌ها از طریق برنامه کاربردی، کنترل شده و به‌صورت پارامتر به یک SP ارسال شوند دیگر مشکلی به وجود نیاید.

    • سلام و تشکر
      بسیار عالی است.
      مورد مشابهی داشتم، ولی چون در ورودی کاربر، مشخص نیست اسم و فامیل کدام است این روش کاربرد نداشت. آیا راهی هست که روی ترکیب دو فیلد ایندکس گذاشته شود؟

      بیصبرانه منتظر قسمتهای بعدی مقاله هستم.

      • سوال شما کمی گنگ است.
        فکر می‌کنم اگر ورودی‌ها از طریق برنامه کاربردی، کنترل شده و به‌صورت پارامتر به یک SP ارسال شوند دیگر مشکلی به وجود نیاید.

    • ضمن تشکر از شما، مطلب عنوان شده خیلی واضح است.

      • از ارسال دیدگاه‌تان بینهایت سپاسگزارم.
        گاهی بسیاری از افراد حرفه‌ای با رعایت نکردن همین نکات به‌ظاهر ساده می‌توانند زمینه‌های بروز عدم کارآیی دیتابیس را فراهم کنند.

    • از ارسال دیدگاه‌تان بینهایت سپاسگزارم.
      گاهی بسیاری از افراد حرفه‌ای با رعایت نکردن همین نکات به‌ظاهر ساده می‌توانند زمینه‌های بروز عدم کارآیی دیتابیس را فراهم کنند.

  • 1
  • 2
هر روز یک ایمیل، هر روز یک درس
آموزش SQL Server بصورت رایگان
همین حالا فرم زیر را تکمیل کنید
دانلود رایگان جلسه اول
نیک آموز علاوه بر آموزش، پروژه‌های بزرگ در حوزه هوش تجاری و دیتا انجام می‌دهد.
close-link
وبینار رایگان ؛ Power BI کلید رقابت شما در دنیا داده‌ها      چهارشنبه 12 اردیبهشت ساعت 15
ثبت نام رایگان
close-image