مفهوم Lookup، اگر تا به حال به مسائل Tuning و Performance در زمینه ی Queryها پرداخته باشید احتمالا با Execution Plan سر و کله زده اید تا ببینید کدام قسمت از Queryتان مشکل دارد و باید آن قسمت را اصلاح کنید و یا دنبال راه حل Indexی باشید. همان طور که می بینید در این Query تقریبا چیزی حدود ۵۰ درصد هزینه صرف Key Lookup شده است ، حال می خواهیم ابتدا ضمن بررسی کردن دلیل به وجود آمدن Lookup راه حل برطرف نمودن آن را نیز ارائه دهیم.
مفهوم Lookup
خوب Lookup به معنای گشتن دنبال چیزی می باشد ، در Lookup اتفاقی که می افتد این است که پایگاه داده SQL Server برای پیدا کردن یک یا چند فیلد نمی تواند از Index تعریف شده استفاده کند و باید برای یافتن آن فیلد و یا فیلدها دوباره در خود جدول بگردد.همانطور که می دانید دو نوع Index داریم ، Clustered و Non Clustered. چون مبحث امروز در مورد Indexها نیست سعی می کنم خیلی خلاصه مفهوم این دو Index را بررسی کنم. در نوع Clustered اتفاقی که می افتد این است که SQL چینش فیزیکی رکوردها را مرتب می کند و چون بحث مرتب سازی می باشد رکوردها تنها می توانند بر اساس یک فیلد مرتب شوند ، در نتیجه Clustered Index روی همان فیلد تعریف می شود ، پس از تعریف Primary Key هم یک Clustered Index تعریف می شود که رکوردها را بر اساس آن Key مرتب می کند.
در نوع ایندکس Non-Clustered روی یک یا چند فیلد می توانیم Index بگذاریم و اتفاقی که می افتد این است که این فیلد ها توسط SQL در مکانی دیگر کپی می شوند و با توجه به ساختاری به نام B-Tree مرتب می شوند. خوب Non Clustered index می تواند روی جداول Heap (جدولی که هیچ نوعی از Index روی آن تعریف نشده است) و یا جداول Clustered تعریف شود. در هر دوی آن ها ما تعداد محدودی از فیلدها را در Index داریم و اگر در شرط SELECT QUERY به فیلدهای بیشتری نیاز باشد SQL مجبور می شود برای یافتن آن فیلدها به خود جدول مراجعه کند و به دنبال آن فیلدها “بگردد” که به این کار به اصطلاح Key Lookup می گویند.
اگر این گشتن روی یک Clustered Table باشد چون به دنبال کلید Indexی که خود جزو Non Clustered نیز هست می گردد به آن Key Lookup گفته می شود و حال اگر این Non Clustered روی Heap Table تعریف شده باشد SQL مجبور است تمامی جدول را برای یافتن فیلد اضافی بگردد که به این عمل هم RID Lookup گفته می شود. شما میتوانید کوئری نویسی را به صورت گامبهگام از نیک آموز فرا بگیرید.
مشاهده کاملترین و بروزترین آموزش sql server در نیک آموز
چگونه می توان Lookup را برطرف کرد؟
ما می توانیم به Non Clustered بگوییم که به جز آن چند فیلدی که در جایی دیگر کپی شده اند یک یا چند فیلد دیگر را نیز در کنار آن ها نگهداری کند به نحوی که این فیلدها در نحوه مرتب سازی تاثیری ندارند و فقط به عنوان فیلدهای اضافی به مابقی فیلدها چسبیده اند ، با این روش SQL وقتی دستور select را چک می کند دیگر نیازی ندارد به خود جدول سر بزند و هرآنچه نیاز دارد در کنار بقیه فیلدها پیدا می کند و هزینه صرف شده جهت Lookup صرفه جویی می شود به این نوع از Indexها Covered Index گفته می شود.
مثال در مفهوم Lookup
در این مثال از دیتابیس AdventureWorks2012 استفاده می کنیم ، می خواهیم دستور زیر را اجرا کنیم ، قبل آن STATISTICS IO را فعال می کنیم تا تعداد صفحات خوانده شده را بتوانیم بررسی کنیم. افراد علاقهمند میتوانند با مطالعه مقاله پرکاربردترین دستورات SQL Server، دانش خود را در زمینه کوئرینویسی گسترش دهند.
<span style="color: #000000;">SET STATISTICS IO ON;
SELECT CustomerID, OrderDate
FROM [AdventureWorks2012].[Sales].[SalesOrderHeader]
WHERE CustomerID = 11000;
<span style="color: #000000;">SET STATISTICS IO ON;
SELECT CustomerID, OrderDate
FROM [AdventureWorks2012].[Sales].[SalesOrderHeader]
WHERE CustomerID = 11000;
</span>
SET STATISTICS IO ON;
SELECT CustomerID, OrderDate
FROM [AdventureWorks2012].[Sales].[SalesOrderHeader]
WHERE CustomerID = 11000;
خوب حالا نتایج STATISTICS IO را ببینیم ، Table ‘SalesOrderHeader’. Scan count 1, logical reads 11, physical reads 0, read-ahead reads برای این واکشی ۱۱ صفحه خوانده شده است. حال نتیجه Execution Plan را با هم ببینیم، مشاهده می شود که ۶۸ درصد هزینه صرف Key Lookup شده است و با اینکه Non Clustered Index تعریف کرده بودیم هنوز هزینه ی زیادی بابت Key Lookup پرداخت می شود. حال Index قبلی را Drop کرده و Index جدیدی با استفاده از مفهوم Covered Index ایجاد می کنیم ، حال دوباره نتیجه STATISTICS IO و Execution Plan را ببینیم ،
Table ‘SalesOrderHeader’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads
<span style="color: #000000;">DROP INDEX Sales.SalesOrderHeader.IX_SalesOrderHeader_CustomerID; CREATE NONCLUSTERED INDEX IX_SalesOrderHeader_CustomerID_OrderDate ON Sales.SalesOrderHeader(CustomerID, OrderDate);</span> <span style="color: #000000;">DROP INDEX Sales.SalesOrderHeader.IX_SalesOrderHeader_CustomerID;
CREATE NONCLUSTERED INDEX IX_SalesOrderHeader_CustomerID_OrderDate
ON Sales.SalesOrderHeader(CustomerID, OrderDate);</span> DROP INDEX Sales.SalesOrderHeader.IX_SalesOrderHeader_CustomerID;
CREATE NONCLUSTERED INDEX IX_SalesOrderHeader_CustomerID_OrderDate
ON Sales.SalesOrderHeader(CustomerID, OrderDate);
|
سخن پایانی
مفهوم Lookup، مشاهده می شود که علاوه بر حذف شدن هزینه Key Lookup تعداد صفحات خوانده شده نیز به عدد ۲ کاهش یافت. این مفهوم میتوانند باعث کاهش عملکرد Queryها شوند، زیرا نیاز به دسترسی به جداول و ایندکسهای مختلف دارند. برای کاهش هزینه Lookupها، میتوانید از ایندکسهای Covering استفاده کنید که شامل تمام ستونهای مورد نیاز در Query هستند و نیاز به Lookup را از بین میبرند. ما در نیک آموز منتظر نظرات ارزشمند شما درباره این مقاله هستیم.
علی تجویدی
با سلام
ممنون از مقاله مفید
جمله شما که در زیر آورده شده صحیح نیست
“حال اگر این Non Clustered روی Heap Table تعریف شده باشد SQL مجبور
است تمامی جدول را برای یافتن فیلد اضافی بگردد که به این عمل هم RID
Lookup گفته می شود.
“
تمامی جدول را نمی گردد و در خیلی موارد RID Lookup هزینه کمتری نسبت به Key Lookup دارد.
با تشکر
مهدی ربانی ذبیحی
با سلام ممنون بابت مقاله خوبتون
فرشید علی اکبری
سلام
فرید طاهری
سلام. با تشکر از دقت شما
اصلاح گردید.
میلاد فیروزی
ممنون
مسعود طاهری
میلاد عزیز متشکرم از مقاله خوبی که در سایت قرار دادید.
sql programmer
با سلام چطور میتونیم کوئری های پراستفاده را پیدا کنیم
میلاد فیروزی
ممنون استاد