مشخصات مقاله
-
1513
-
0.0
-
4574
-
0
-
0
اجتناب از استفاده از نابرابری در عبارت WHERE
اجتناب از استفاده از نابرابری در عبارت WHERE
در بسیاری از موارد وقتی از اپراتور <> استفاده می کنیم (یا هر اپراتور دیگری در ارتباط با NOT، به عنوان مثال NOT IN) جستجوهای ایندکس اجرا نخواهند شد و در عوض اسکن یک جدول یا ایندکس لازم می باشد.
توضیحات
برای این مثال اجازه بدهید یکی از جدول های تست خود را آپدیت کنیم تا داده را کمی تغییر دهیم. و همچنین به ستونی که در عبارت WHERE استفاده خواهد شد، در جدول یک ایندکس اضافه می کنیم.
UPDATE [dbo].[Child] SET IntDataColumn=60000 UPDATE [dbo].[Child] SET IntDataColumn=3423 WHERE ParentID=4788 UPDATE [dbo].[Child] SET IntDataColumn=87347 WHERE ParentID=34268 UPDATE [dbo].[Child] SET IntDataColumn=93423 WHERE ParentID=84938 UPDATE [dbo].[Child] SET IntDataColumn=5564 WHERE ParentID=74118 CREATE NONCLUSTERED INDEX idxChild_IntDataColumn ON [dbo].[Child] ([IntDataColumn],[ParentID]) INCLUDE ([ChildID]) -- cleanup statements --DROP INDEX Child.idxChild_IntDataColumn
اکنون جازه بدهید نگاهی به یک query ساده داشته باشیم که همه ی رکوردها را در IntDataColumn <> 60000 بازمی گرداند. در اینجا آنچه را می بینید که به نظر می رسد:
SELECT P.ParentID,C.ChildID,C.IntDataColumn FROM [dbo].[Parent] P INNER JOIN [dbo].[Child] C ON P.ParentID=C.ParentID WHERE C.IntDataColumn <> 60000
با نگاه کردن به طرح توضیح (explain plan) برای این query، متوجه نکته ی بسیار جالبی خواهیم شد. از آنجایی که optimizer (بهینه ساز)، روی داده در این ستون دارای استاتیک هایی می باشد، query را بازنویسی کرده تا عبارت های مجزای < and > استفاده کند. این مسئله را به طور دقیق روی Index Seek زیر تیتر Seek Predicate مشاهده می کنیم.
اکنون اجازه بدهید ببینیم اگر دو عبارت <> داشته باشیم، چه اتفاقی می افتد، مانند زیر:
SELECT P.ParentID,C.ChildID,C.IntDataColumn FROM [dbo].[Parent] P INNER JOIN [dbo].[Child] C ON P.ParentID=C.ParentID WHERE C.IntDataColumn <> 60000 and C.IntDataColumn <> 5564
با نگاه به explain plan برای این query، مشاهده می کنیم که optimizer در عبارت WHERE تغییراتی انجام داده است. این برنامه اکنون از مقدار جدید که درSeek Predicate اضافه کردیم و یا مقدار اصلی، مانند دیگر Predicate ها استفاده می کند. هر دو تغییر کرده اند تا از عبارت های مجزای < and > استفاده کنند.
گرچه تغییرات ایجاد شده به وسیله ی optimizer ، با جلوگیری از index scanقطعا به query کمک کرده، اگر بهترین اجرای ممکن را می خواهید، همیشه بهتر است از یک اپراتور تساوی مانند = یا IN در query خود استفاده کنید. قبل از اعمال تغییرات مشابه، نکته ای که باید به آن توجه کنید این است که باید اطمینان اصل کنید که درک خوبی از داده ی خود دارید، زمانیکه جدول داده می تواند روی نتایج query شما تاثیر بگذارد. با آنچه گفته شده و ارائه شده است می دانیم که جدول ما رکوردهای کمی دارد که شرایط WHERE را کامل می کند، اجازه بدهید آن را به یک اپراتور تساوی تغییر داده و تفاوت اجرا را مشاهده کنیم.
در اینجا query جدید را مشاهده می کنید:
SELECT P.ParentID,C.ChildID,C.IntDataColumn FROM [dbo].[Parent] P INNER JOIN [dbo].[Child] C ON P.ParentID=C.ParentID WHERE C.IntDataColumn IN (3423,87347,93423)
با نگاه کردن به explain plan برای این query، متوجه می شویم که این برنامه نیز در حال انجام جستجوی ایندکس می باشد، اما با نگاه عمیق تر به Seek Predicate ، متوجه می شیم که در حال استفاده از اپراتور تساوی می باشد که باید بسیار سریعتر باشد:
اکنون اجازه بدهید برای این دو query نگاهی به نتایج SQL Profiler بیندازیم، در زیر مشاهده می کنیم که مثالی که از اپراتور تساوی استفاده می کند، سریعتر اجرا شده و به منابع کمتری نیاز دارد. نکته: هر دو query یک مجموعه نتیجه را گزارش می دهند.