خانه SQL Server اصلاح آرگومان جستجو در کوئری SQL Server افزایش سرعت SQL Server نوشته شده توسط: تورج عزیزی تاریخ انتشار: ۲۶ دی ۱۳۹۴ آخرین بروزرسانی: ۱۰ اردیبهشت ۱۴۰۱ زمان مطالعه: 5 دقیقه ۵ (۱) سلام دوستان امروز می خواهم راجع به مشکل بخصوصی که به indexing در SQL Server مربوط می شود صحبت کنم. تعریف مشکل نمونه کوئری زیر را در نظر بگیرید، مثل این کوئری را صدها بار در SQL Server دیده اید: -- Results in an Index Scan SELECT*FROM Sales.SalesOrderHeader WHEREYEAR(OrderDate)= 2005 ANDMONTH(OrderDate)= 7 GO با این کوئری ساده ما اطلاعات فروش را راجع به ماه خاصی از یک سال خاص را درخواست می کنیم.خیلی پیچیده نیست. اما متاسفانه این کوئری خیلی خوب عمل نمی کند. حتی با وجود یک Nonclustered Index روی ستون OrderDate. وقتی به پلن اجرا نگاه می کنید، می توانید ببینید که Query Optimizer از Nonclustered Index که روی OrderDate تعریف شده استفاده کرده اما متاسفانه SQL Serverیک اسکن کامل به جای اینکه یک عمل Seek موثر از ایندکس انجام میدهد. در حقیقت این یک مشکل برای SQL Server محسوب نمی شود، این روشی است که دیتابیس های رابطه ای کار می کنند و فکر می کنند! به محض اینکه یک عبارت (فراخوانی توابع یا محاسبات) روی یک ستون دارای ایندکس (که Search Argument هم نامیده می شود) اعمال کنید، موتور دیتابیس باید آن ایندکس را Scan کند، به جای اینکه یک عمل Seek انجام دهد. راه حل برای اینکه عمل اسکن ایندکس به Seek تغییر کند، باید کوئری را طوری بنویسیم که دیگر تابع DATEPARTفراخوانی نشود: -- Results in an Index Seek SELECT*FROM Sales.SalesOrderHeader WHERE OrderDate >='20050701'AND OrderDate <'20050801' GO و همانطوری که در کوئری بازنویسی شده می بینید، این کوئری نتایج مشابهی برمی گرداند، اما ما فقط فراخوانی تابع DATEPART را حذف کرده ایم. وقتی به پلن اجرا نگاه می کنید، می بینید که SQL Server یک عمل Seek انجام می دهد- در این کوئری عمل Seekاصطلاحاً Partial Range Scanنامیده می شود: SQL Server مقدار اول را جستجو می کند و عمل اسکن را تا زمانی که به آخرین مقدار درخواستی در محدوده نرسیده ادامه می دهد. اگر مجبور هستید در متن ستون های ایندکس دار فراخوانی کنید، شما باید مطمئن شوید که این فراخوانی به تابع در سمت راست ستون شما در کوئری اجرا می شوند. اجازه دهید به این مثال نگاهی بیندازیم. اجازه دهید به کوئری زیر نگاهی بیندازیم. کوئری زیر ستون دارای ایندکس CreditCardIDرا به دیتا تایپ CHAR(4)تبدیل می کند: -- Results in an Index Scan SELECT*FROM Sales.SalesOrderHeader WHERECAST(CreditCardID ASCHAR(4))='1347' GO وقتی نگاهی دقیق تر به پلن اجرا دارید، می توانید ببینید SQL Server ایندکس Nonclustered را به تمامی اسکن کرده است. اگر شما این تبدیل را در سمت راست ستون ایندکس دار در کوئری اجرا کنید، می توانید دوباره می توانید فراخوانی روی ستون ایندکس دار را حذف کنید و SQL Server خواهد توانست عمل Seek انجام دهد: -- Results in an Index Seek SELECT*FROM Sales.SalesOrderHeader WHERE CreditCardID =CAST('1347'ASINT) GO خلاصه همان طور که در این پست دیدید، بسیار حائز اهمیت است که هیچ تابعی مستقیم یا غیر مستقیم روی ستون های دارای ایندکس فراخوانی نکنید. در غیر اینصورت SQL Server باید ایندکس را Scan کند، به جای اینکه یک عمل Seek موثر انجام دهد. چه رتبه ای میدهید؟ میانگین ۵ / ۵. از مجموع ۱ اولین نفر باش معرفی نویسنده مقالات 18 مقاله توسط این نویسنده محصولات 0 دوره توسط این نویسنده تورج عزیزی معرفی محصول مسعود طاهری آموزش ۳ در ۱ Performance Tuning در SQL Server 6.700.000 تومان مقالات مرتبط ۰۲ آبان SQL Server ابزار Database Engine Tuning Advisor؛ مزایا، کاربردها و روش استفاده تیم فنی نیک آموز ۱۵ مهر SQL Server معرفی Performance Monitor ابزار مانیتورینگ SQL Server تیم فنی نیک آموز ۱۱ مهر SQL Server راهنمای جامع مانیتورینگ بکاپ ها در SQL Server تیم فنی نیک آموز ۰۸ مهر SQL Server Resource Governor چیست؟ آشنایی با نحوه پیکربندی و اهمیت های آن تیم فنی نیک آموز دیدگاه کاربران لغو پاسخ دیدگاه نام و نام خانوادگی ایمیل ذخیره نام، ایمیل و وبسایت من در مرورگر برای زمانی که دوباره دیدگاهی مینویسم. موبایل برای اطلاع از پاسخ لطفاً مرا با خبر کن ثبت دیدگاه Δ احمد رضاپور ۰۴ / ۱۱ / ۹۴ - ۰۳:۴۱ بسیار خوب بود؛ با تشکر.. پاسخ به دیدگاه حجازی ۰۳ / ۱۱ / ۹۴ - ۰۴:۳۳ تشکر به نکته ریز و جالبی اشاره کردید پاسخ به دیدگاه ساقی ۰۳ / ۱۱ / ۹۴ - ۱۰:۴۶ متشکریم.نکته خیلی عالی بود پاسخ به دیدگاه فرزین ۲۸ / ۱۰ / ۹۴ - ۰۸:۴۰ بسیار عالی پاسخ به دیدگاه مهدی ربانی ذبیحی ۲۷ / ۱۰ / ۹۴ - ۰۳:۳۱ سلام بسیار عالی و کاربردی بود ممنون پاسخ به دیدگاه فرشید علی اکبری ۲۷ / ۱۰ / ۹۴ - ۰۲:۲۲ سلام بسیار عالی؛ مطلب خوبی بود. پاسخ به دیدگاه تورج عزیزی ۲۷ / ۱۰ / ۹۴ - ۰۹:۴۷ سلام محمد حسین جان عزیز، شما اگر تابعی روی یک ستون ایندکس دار در یک شرط اعمال کنید، ساختار B-Tree از حالت خودش خارج میشه یعنی نمیشه مطمئن شد که سمت چپ درخت حتماً مقادیر کمتری نسبت به سمت راست درخت داره…. وبنابراین تمام نودهای درخت باید بررسی بشن. پاسخ به دیدگاه محمدحسین عبدالهی ۲۷ / ۱۰ / ۹۴ - ۱۰:۳۰ سلامتشکر آقای عزیزیتوضیح خلاصه و مفیدی بود پاسخ به دیدگاه محمدحسین عبدالهی ۲۷ / ۱۰ / ۹۴ - ۰۰:۲۷ آقای تورج عزیزی مجدد تشکر می کنم بابت مقاله خوبتون من دو تا کوئری شما رو در AdventureWorks2014 تست کردم در ابتدا هیچ تفاوتی مشاهده نشد.بعد برای جدول SalesOrderHeader یک ایندکس گذاشتم و تفاوت اساسی مشاهده شد! (۹۳% به ۷%) به این صورت نتیجه گیری کردم : در شرط جستجو ، زمانی که تبدیل نوع یک ستون – ایندکس گزاری شده – در سمت راست باشد اس کیو ال سرور از Index Seek برای نمایش نتیجه استفاده می کند. ( نکته : فقط برای ستون ایندکس گذاری شده این موضوع تأثیر گذار هست) می خواستم ببینم درست هست این نتیجه گیری؟ پاسخ به دیدگاه مسعود طاهری ۲۷ / ۱۰ / ۹۴ - ۰۷:۰۸ سلام در مقاله به همین موضوعی که شما فرمودید اشاره شده و نتیجه گیری شما درست است به مثال های زیر هم توجه کنید ad: Select … WHERE isNull(FullName,’Ed Jones’) = ‘Ed Jones’ Fixed: Select … WHERE ((FullName = ‘Ed Jones’) OR (FullName IS NULL)) Bad: Select … WHERE SUBSTRING(DealerName,4) = ‘Ford’ Fixed: Select … WHERE DealerName Like ‘Ford%’ Bad: Select … WHERE DateDiff(mm,OrderDate,GetDate()) >= 30 Fixed: Select … WHERE OrderDate < DateAdd(mm,-30,GetDate()) ضمنا مفهوم SARGable predicate را در نظر داشته باشید http://www.sqlusa.com/bestpractices/sargable/ پاسخ به دیدگاه محمدحسین عبدالهی ۲۷ / ۱۰ / ۹۴ - ۰۹:۵۴ تشکر استاد طاهری پاسخ به دیدگاه سعید شیرزادیان ۲۷ / ۱۰ / ۹۴ - ۰۰:۱۳ سلام مقاله خیلی کاربردی و مفید بود پاسخ به دیدگاه محمدحسین عبدالهی ۲۷ / ۱۰ / ۹۴ - ۰۰:۳۵ بسیار عالیمتشکرمفقط اگر میشد بعد از بندی که اشاره کردین به Partial Range Scan تصویر نتیجه رو هم نمایش میدادین به نظرم بهتر میشد. پاسخ به دیدگاه 1 2