PDA

View Full Version : روشهای بالا بردن Performance در Query ها



Kamyar.Kimiyabeigi
چهارشنبه 23 خرداد 1386, 09:47 صبح
جناب آقای ثباتی عزیز من این مطالب رو از یک سایت استخراج کردم و میدونم که قبلا" هم در برنامه نویس توسط دوستان قرار داده شده منتها میخوام شما نظر بدین که کدومشون درسته و کدومشون غلط ممنون.


1. تا جائیکه امکان دارد سعی کنید از عبارتWHERE در دستورات SELECT خود استفاده کنید.

2. از Inner Join استفاده نکنید.

3. تا حد امکان از بکارگیری Cursor اجتناب کنید.

4. در مورد اینکه آیا SELECT شما واقعا به DISTINCT نیاز دارد یا نه توجه کنید . در جایی که نیاز نیست از آن به هیچ عنوان استفاده نکنید.

5. در عبارت SELECT خود ، فقط اسامی فیلدهایی را ذکر کنید که استفاده می کنید. لذا از عبارت SELECT * تا حد امکان خودداری کنید.

6. دستور SET ROWCOUNT همان کاری را انجام می دهد که گزینه TOP در دستور SELECTاما گزینه TOP به مراتب کاراتر است.

7. تا حد امکان از EXISTS و IN به جای EXISTS NOT و NOT IN استفاده کنید زیرا Performance سیستم را افزایش می دهند.

8. از Constraint ها استفاده کنید. مانند گزینه های Constraint و یا Default ها.

9. از چند Constraint برای انجام یک کنترل استفاده نکنید. مثلا اگر از محدودیتهای Primary Key و Foreign Key برای کنترل جامعیت ارجاعی(Referential Integrity) استفاده می کنید، کنترل این مطلب در Trigger نیز تنها یک بار اضافی به سیستم تحمیل می کند.

10. زمانی که برای انجام یک درخواست هم می توان از Join استفاده کرد هم از Sub Query ، استفاده از Join توصیه می شود چون سریعتر است.

11. اگر در عبارت خود هم می توانید از IN استفاده کنید هم از EXISTS ، ترجیحا از EXISTS استفاده کنید چون کارا تر و سریتر عمل می کند.

12. وقتی هم امکان اینرا دارید که از IN استفاده کنید ، هم از BETWEEN ، از BETWEEN استفاده کنید.

13. تا جائیکه امکان دارد ، سعی کنید از SUBSTRING( ) در عبارت WHERE خود استفاده نکنید.زیرا باعث می شود که جدول Scan شود به جای اینکه از Index استفاده کند.

14. تا جائیکه امکان دارد از توابع تبدیلی در شرط WHERE استفاده نکنید.

15. با اینکه استفاده از View ها آسان است ، اما کارایی سیستم را کم می کنند.به جای استفاده از View از Stored Procedureها استفاده کنید.

16. از View های تودر تو استفاده نکنید.(در صورتیکه به توصیه 15 عمل نمی کنید !!! ).

17. تا زمانی که واقعا نیازی ندارید از DISTINCT یا ORDER BY استفاده نکنید.

18. اگر در برنامه تان از جستجوی متنی wildcardی روی CHAR یا VarCharزیاد استفاده می شود (Like % ) ، از امکانات Full Text Search استفاده کنید.

19. شما می توانید از GROUP BY با / بدون توابع Aggregation استفاده کنید. اما اگر می خواهید بالاترین کارایی را داشته باشید ، از GROUP BY بدون توابع Aggregation استفاده نکنید.

20. تا آنجا که امکان دارد از Derived Table ها به جای Temporary Table ها استفاده کنید.

21. اگر در شرط WHERE از توابعی روی فیلد ها ، استفاده شود که Non-Search باشند ،باعث پایین آمدن کارایی می شود.اگر بتوانید به شکلی شرط WHERE را طوری بازنگری کنید که فیلد و تابع جدا گانه باشند،در این صورت Query می تواند از Index موجود استفاده کرده و کارایی را افزایش دهید.



SELECT ID, FirstName, LastNamed From Members WHERE DATEDIFF(yy, DateofBirth, GetDate()) > 21




SELECT ID, FirstName, LastNamed From Members WHERE DateofBirth < DATEADD(yy, -21, GetDate())


22. ایندکس باید روی تمام فیلدهایی که مرتب در WHERE ، ORDER BY ، GROUP BY ، TOP و DISTINCT استفاده می شوند ، زده شود.

23. طبق قانون Thumb ،تمام جداول حداقل یک Clustered Index داشته باشند.عموما ، نه همیشه ، Clustered Index باید روی فیلدهایی زده شوند که مقادیرش به صورت یکنواخت افزایش پیدا می کنند ، مانند فیلدهای Identity و یا فیلدهایی که مقادیرشان افزایش می یابند و Unique هستند. در بسیاری از شرایط Primary Key بهترین انتخاب برای Clustered Index است.

24. روی جداول OLTP ، ایندکس نزنید چون هر ایندکس زمان اجرای دستورات DML را افزایش می دهد.

25. دقت کنید که به طور تصادفی ، ایندکس مشابه روی جداول نزنید . این اتفاق ممکن است به سادگی اتفاق بیافتد. برای مثال ، شما یک Unique یا Primary Key روی یک فیلد تعریف می کنید، در اینصورت اتوماتیک ایندکس هایی روی این فیلد زده می شود اما اگر شما به این مسئله توجه نکنید و جداگانه روی این فیلد اینکدس بزنید، دچار مشکل ایندکس های تکراری می شوید.

26. عموما در موارد زیر ایندکس زده نمی شود:
• اگر Query Optimizer از ایندکس استفاده نکند. مثلا اگر جدول کوچک باشد، اکثرا از ایندکس استفاده نمی شود.
• فیلد یا فیلدهایی که قرار است در ایندکس باشند ،عریض باشند.
• اگر فیلدها از نوع Text یا Ntext یا Image باشند.
• اگر از جدول به ندرت استفاده شود.

27. گاهی اوقات ایده خوبی است که یک ایندکس مرکب را به چندین ایندکس تک فیلدی تجزیه کنید چون عملا فیلد اول توسط Query Optimizer استفاده می شود البته این بدین معنا نیست که همیشه Single Index از Composite Index ها بهتر عمل می کنند.فقط با تست کردن می توانید بفهمید که کدامیک برای جدول شما کارایی بیشتری دارد.

28. اگر دو یا چند جدول دارید که مرتبا آنها را به یکدیگر Join می کنید ، بهتر است روی فیلدهایی که در Join شرکت دارند ایندکس بزنید.

29. تا جائیکه امکان دارد ایندکس Unique ایجاد کنید. زیرا SQL Server روی ایندکسهای Unique سریعتر از ایندسهای غیر Unique می تواند جستجو کند.

30. از فیلدهای Float و Real برای Primary Key استفاده نکنید زیرا یک Overhead غیر ضروری به سیستم تحمیل می کند که کارایی سیستم را می کاهد.

31. هیچگاه روی فیلدهایی که روی آنها Non-Clustered Index زده شده است ، Clustered Index نزنید.

32. از Clustered Index زدن روی فیلدهایی که مرتب Update می شود خودداری کنید زیرا هروقت فیلدی که در یک Clustered Index استفاده شده تغییر می کند، تمام Non-Clustered Index ها هم باید Update شوند.

33. فیلد یا فیلدهایی را برای Clustered Index انتخاب کنید که شامل اطلاعاتی باشد که در Query ها بیشتر Search می شوند.

34. Primary Key ایی که شما روی جداولتان استفاده می کنید ، حتما نباید همیشه Clustered Index باشند زمانی Primary Key را Clustered Index کنید که مرتبا Range Query روی Primary Key انجام می دهید یا می خواهید خروجیتان بر اساس Primary Key مرتب شود.

35. تا جاییکه امکان دارد از ایندکس زدن روی فیلد GUID خودداری کنید.

36. در اول تمام Stored Procedure های خود از دستور SET NOCOUNT ON استفاده کنید.

37. اگر Stored Procedure شما به صورت دینامیک باشد و یا شرایط WHERE آن در هر بار اجرا
تغییر می کند، از With Recompile در Stored Procedure خود استفاده کنید.

38. اگر می خواهید اطلاعات را به صورت رشته ای در جدول ذخیره کنید ، و طول آن کمتر از 8000 است ، از نوع Char یا VarChar به جای Text استفاده کنید.

39. اگر در برنامه تان از Temporary Table زیاد استفاده می کنید، به جای آن سعی کنید از متغیرهایی از جنس Table استفاده کنید.

40. DateTimeرا هیچگاه به عنوان Primary Key در نظر نگیرید.

41. اگر این انتخاب را دارید که برای ملزم کردن Rules و Default ها از Trigger یا CHECK Constrain استفاده کنید ترجیحا از CHECK Constrain استفاده کنید.

42. برای کاهش Overhead ، کمترین کد ممکن را در Trigger بنویسید.

43. تا جاییکه ممکن است از Roll Back کردن تا حد امکان در Trigger خودداری کنید سعی کنید قبل از اینکه Trigger اجرا شود ، مشکل را برطرف کنید.

44. برای ایجـاد جـداول موقت ( در صورتیکه چاره ای جز استفـاده از آنها ندارید ) ، از SELECT INTO استفاده نکنید.

AminSobati
پنج شنبه 24 خرداد 1386, 00:41 صبح
1) درست
2) خنده دار بود! Join بهترین الگوریتمها رو برای اجرا داره (مگر موارد بسیار نادر که قابل اغماضه)
3) درست
4) درست
5) درست
6) درست، ولی SET ROWCOUNT هم کاربرده خودش رو داره
7) نه الزاما
8) اگر لازمه استفاده کنید!
9) نه همیشه
10) درسته (مورد 2 رو نقض کرده خودش!)، ولی موارد استثناء هم وجود داره
11) نه الزاما. در بسیار اوقات Plan در هر دو حالت یکسان تولید میشه
12) ربطه IN به BETWEEN رو متوجه نمیشم!
13) موضوع تنها Substring نیست، در حالتهای دیگه هم میتونه اتفاق بیافته. چون Optimizer نیاز داره عبارت مورد جستجوی شما با عبارتی شروع شده باشه که در ایندکس موجوده. پس وقتی وسط کلمه ای رو بخواهید، ایندکس کمکی نمیکنه. این حالت برای تابع RIGHT هم میتونه اتفاق بیافته.
14) کلا هر چی کمتر بهتر، اما فقط Where نیست
15) غلط
16) دلیلی براش سراغ ندارم که بگم درسته
17) درست (Distinctش تکراری بود!)
18) اگر جستجو در حدی هست که دردسر نگهداری FTS رو داره، درسته
19) در بعضی موارد GROUP BY بدون Aggregate بهترین راه حله (به تناسب نیاز و هدف)
20) درست
21) موافقم، به شماره 13 ربط داره
22) درست، اما با ده ها اما و اگر!
23) درست. یک PK خوب میتونه دو خصوصیت مهم داشته باشه: Ever Increasing و Narrow. اما شرایط نه چندان نادری وجود داره که PK رو Clustered نمیکنیم. همچنین شرایط خاصی وجود داره که Ever Increasing بودن برای PK بسیار مضره و روی هارد دیسک Hot Spot بوجود میاره. این مورد باید به تناسب سناریو بحث بشه.
24) از اون حرفها بود! در OLTP هزینه دستورات DML برای Index رو ارزش داره که متحمل بشیم
25) درست
26) تقریبا درست (با کمی اما و اگر!)
27) درست، اما تشخیص اینکه چه موقع Composite به Single تبدیل بشه کمی کاره فنی هستش
28) درست، اما نوع ایندکس بسیار مهمه
29) درست، به شرطی که فیلد Unique باشه واقعا
30) اطلاعی از Overhead ندارم، شاید درست باشه
31) البته یک Clustered بیشتر نمیشه روی هر جدول درست کرد
32) قبول، اما گاهی اوقات اجتناب ناپذیر شاید باشه
33) درست
34) درست
35) دلیلی برای اجتناب از این کار سراغ ندارم. اگر میگفت Clustered Index نزنید شاید منطقی تر بود
36) درست
37) غلط.
38) درست
39) درست
40) درست
41) درست
42) چشم بسته غیب فرمودند!
43) همیشه امکان پذیر نیست
44) دلیلی برای تاییدش سراغ ندارم

supporter
پنج شنبه 24 خرداد 1386, 18:54 عصر
در رابطه با مورد 44 :


Do not use the SELECT INTO statement to create your temp table. The SELECT INTO should be avoided at all costs in your coding due to the locking it places on system objects while it determines how to build the table. Take the time to script the temporary table out and use a separate INSERT INTO to populate the table. I will qualify this with that you can use a SELECT INTO if it includes WHERE 1=0 to create a table in the quickest way possible, but don't do this just to save a few keystrokes.

AminSobati
پنج شنبه 24 خرداد 1386, 20:17 عصر
صحبتش غیره منطقی نیست اما مدت زمانی که صرف بدست آوردن اطلاعات سیستمی برای ساخت جدول موقتی میشه، واقعا ناچیزه. از طرفی حتی اگر جدول رو ساخته باشیم و INSERT....SELECT انجام بدیم، در حین Select هم باز باید به جداول سیستمی رجوع کنه تا جنس هر فیلد رو بدست بیاره و با مقصد مقایسه کنه تا جنس اطلاعات از Select با جدول مقصد مغایرت نداشته باشه. ولی این کنترل در Select Into نیازی نیست.
در کل، عقیده دارم موشکافی در این مورد لزومی نداره چون تفاوت بسیار ناچیزه..

supporter
پنج شنبه 24 خرداد 1386, 22:15 عصر
به نظر شما منظورش این نیست که در حالت اول (Select ... Into) متناسب با تعداد رکوردهایی که باید در temp table درج بشن مدت زمان Lock شدن جداول سیستمی هم تغییر می‌کنه و در مواقعی که تعداد این رکوردها زیاده جداول سیستمی هم برای مدت طولانی Lock می‌شن.

AminSobati
پنج شنبه 24 خرداد 1386, 22:39 عصر
due to the locking it places on system objects while it determines how to build the table
[/LEFT]
از این مطلب برداشت من این هست که Lock فقط در زمان تشکیل فیلدهای جدول جدید نگه داشته میشه، نه در کل زمانی که رکوردها هم درج میشن. اگر در تمام مدت ورود رکوردها Lock وجود داشته باشه چندان مکانیزم معقولی نیست

AminSobati
پنج شنبه 24 خرداد 1386, 22:52 عصر
این تست رو هم میشه انجام داد:

کاربر اول:
begin tran
select * into #customers2 from customers

کاربر دوم:
begin tran
select * into #orders2 from orders

در اینجا کاربر دوم با اینکه به جداول سیستمی نیاز داره اما Block نمیشه

مهدی نان شکری
یک شنبه 14 مرداد 1386, 08:45 صبح
با سلام
آقای ثباتی اگه امکان داره در مورد مورد 15 کمی توضیح دهید. ممنون.