اگر * Select به همراه Order By انتخاب کنیم، چه اشکالی داره ؟
در مطلب دیگری به تاثیر order by در مرتب بودن خروجی دیتا اشاره کردیم، حالا سعی می کنیم بررسی کنیم که بکارگیری order by به همراه * select چه تاثیری روی اجرا کوئری در SQL Server داره و راه درست بکارگیری اون چیه.
با بررسی کوئری پلن هر دو کوئری می بینیم که Base هر دو کوئری یه چیزه، اسکن ایندکس کلاستر، مرتب سازی و نمایش خروجی. با این تفاوت که تو کوئری دوم، با توجه به هزینه بالایی که کوئری داره، عملیات به صورت Parallel بین Core های CPU تقسیم شده. احتمالا در نگاه اول میگید که خب جفت این دو تا کوئری دارن از ایندکس Cluster میخونن و به همه دیتا دسترسی دارن اما * Select میتونه دیتای بیشتری رو بخونه
ساختار جدول User رو ببینید:
اگه دقت کنید، می بینید که فیلد AboutMe از نوع Nvarchar(max) هست، به این معنا که ممکنه طول ش اونقدری بزرگ شه که تو Page های 8 کیلوبایتی جا نشه، اگه طول ش کمتر از 8 کیلو بایت باشه، با مکانیزمی مشابه بقیه فیلدها، ذخیره و بازیابی میشه اما اگه طولش بیشتر شه تو Page های از نوع LOB (Large Object) ذخیره میشه و طبیعتا خوندن و بازیابی LOB هزینه ای رو به CPU متحمل میکنه پس:
وقتی Select * مینویسیم SQL مجبوره تمامی Page ها رو بخونه حتی LOB ها رو در حالیکه در Select Id فقط Page های معمولی رو میخونه ، * Select میتونه مرتب سازی بیشتری انجام بده
احتمالا براساس چیزی که تو کوئری نوشته شده (Order by LastAccessDate) این تصور ایجاد میشه که SQL ستون LastAccessDate رو تو یه فضای جداگانه مرتب میکنه و بعد بین اون فضا و ایندکس Cluster سوئیچ می کنه تا مابقی فیلدها رو استخراج کنه، نه اینطور نیست، چون این سوئیچ کردن هزینه زیادی براش داره در نتیجه کل دیتا رو میگیره و مرتب سازی رو انجام میده نتیجتا اینکه CPU و Memory زیادی درگیر اجرای عملیات Sort میشه. به همین خاطره که تو کوئری پلن کوئری دوم، 97 درصد هزینه مربوط به عملگر Sort هست ، * Select میتونه مدت بیشتری طول بکشه تا خروجی رو نشون بده
هر دوی این کوئری ها داره از ایندکس Cluster استفاده میکنه که دیتا هم همراهشه اما انتقال همه اطلاعات تحت شبکه زمان برتر خواهد بود تا انتقال فقط یک فیلد.
منبع :