۱۳۸۷/۰۹/۰۵

چرا نبايد از كوئري‌هاي select * استفاده كرد؟


عموما اولين پاسخي كه به اين سؤال داده مي‌شود اين است كه اين نوع كوئري‌ها اطلاعات زيادي را باز مي‌گردانند و در نتيجه ترافيك شبكه بي‌جهت افزايش خواهد يافت. اما اگر طراحي ديتابيس صحيح بوده و اصول نرمال سازي در آن پياده سازي شده باشد، اين پاسخ آنچنان صادق نخواهد بود (زيرا جداول اينگونه ديتابيس‌ها از تعداد فيلدهاي بسياري تشكيل نخواهند شد). براي مثال به نتيجه اجراي كوئري‌هاي زير بر روي ديتابيس AdventureWorks با 89 هزار ركورد، دقت بفرمائيد:
SELECT * FROM Production.TransactionHistoryArchive
WHERE ReferenceOrderID < 100

SELECT ReferenceOrderLineID FROM Production.TransactionHistoryArchive
WHERE ReferenceOrderID < 100

اختلاف ترافيك شبكه در اين مثال تنها 15K يا حدودا 10 درصد است (180K در مقابل 165K). هر چند ارزش بررسي و برطرف كردن را دارد اما تفاوت حاصل آنچنان قابل ملاحظه نيست.
مهم‌ترين دليلي كه اينجا بايد به آن دقت داشت، تفاوت چشمگير execution plan اين دو كوئري (Ctrl-L) و بحث index coverage است. اس كيوال سرور براي اجراي بهينه كوئري‌ها از ايندكس‌هاي موجود استفاده خواهد كرد. اگر ايندكس تعريف شده از تمامي فيلدهاي درخواستي شما تشكيل شده باشد، ديگر حتي به سراغ جدول هم نخواهد رفت (به اين مفهوم، پوشش ايندكسي گفته مي‌شود).



براي توليد تصوير فوق، كليدهاي Ctrl+L را در management studio فشار دهيد.
اين ديتابيس را از آدرس زير مي‌توانيد دريافت كنيد:
http://www.codeplex.com/MSFTDBProdSamples

كوئري اول از مزاياي پوشش ايندكسي برخودار نخواهد بود (از روش جستجوي Clustered Index استفاده مي‌كند) و در حالت دوم از Index Seek استفاده مي‌گردد. حالت Index Seek يك‌صد بار بهينه‌تر از استفاده از Clustered Index عمل مي‌كند زيرا در حالت كوئري اول بايد تمامي ركوردهاي جدول بررسي شوند (اين عدد از مقايسه نتايج execution plan بدست آمده است).
تنها در صورتيكه بر روي تمامي فيلدهاي جدول ايندكس تعريف كرده باشيد (كه اصلا توصيه نمي‌شود)، كوئري اول توسط ايندكس‌ها پوشش داده شده و سريع اجرا خواهد شد.
بنابراين اگر از كندي اجراي كوئري‌ها با تعداد ركورد بالا شكايت داريد بهتر است نگاهي به نحوه تعريف آنها داشته باشيد و تنها فيلدهايي را در كوئري تعريف كنيد كه به آنها نياز داريد. در اين حالت از مزاياي پوشش ايندكسي برخودار شده ، كوئري‌هاي سريعتري را خواهيد داشت و همچنين در اين حالت ميزان مصرف CPU و حافظه نيز بر روي سرور كمتر خواهد بود.
همچنين در حالت كوئري‌هايي از نوع دوم ذكر شده، موتور بهينه ساز اس كيوال سرور پيشنهادات بهتري را براي ايجاد ايندكس‌هاي جديد و گوشزد نمودن كمبود آنها با ارائه included columns مناسب، ارائه مي‌دهد.
بعلاوه مشخص ساختن تعداد دقيق فيلدهاي مورد نياز، نگهداري برنامه را ساده‌تر ساخته و فيلدهاي اضافه شده آتي سبب تغيير رفتار كوئري‌ها برنامه نخواهند شد و استفاده نكردن از آن نشانه اين است كه هيچ برآوردي از ابعاد واقعي كار در دست نيست.

مآخذ:
Speed Up Your Site! 8 ASP.NET Performance Tips
The real reason SELECT * queries are bad: index coverage