<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>&#8235;Madeira &#187; יוסי חקיקת&#8236;</title>	<atom:link href="http://www.madeira.co.il/author/yossih/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.madeira.co.il</link>
	<description>&#8235;SQL Server Services&#8236;</description>	<lastBuildDate>Sat, 19 May 2012 09:04:40 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>he</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>&#8235;Page Life Expectancy Counter- Case Study&#8236;</title>		<link>http://www.madeira.co.il/case-study-page-life-expectancy-counter/</link>
		<comments>http://www.madeira.co.il/case-study-page-life-expectancy-counter/#comments</comments>
		<pubDate>Sun, 18 Mar 2012 20:23:32 +0000</pubDate>
		<dc:creator>&#8235;יוסי חקיקת&#8236;</dc:creator>				<category><![CDATA[מקודמות]]></category>
		<category><![CDATA[Performance Tuning]]></category>
		<category><![CDATA[Troubleshooting]]></category>

		<guid isPermaLink="false">http://www.madeira.co.il/?p=4604</guid>
		<description><![CDATA[&#8235;האם קרה לכם שמדד ה- Page Life Expectancy צנח אל רמות נמוכות מאד בפתאומיות?? בפוסט זה אציג Case Study שהתרחש אצל אחד מלקוחותינו, כאשר הבעיה כאמור הייתה, צניחה חדה ולא צפויה של מדד זה. רוצים לדעת איך ניתן לטפל בבעיה זו?? כנסו!! &#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p><img src='http://www.madeira.co.il/wp-content/plugins/simple-post-thumbnails/timthumb.php?src=/wp-content/thumbnails/4604.jpg&amp;w=214&amp;h=129&amp;zc=1&amp;ft=jpg' alt='post thumbnail' /></p>
<p>האם כבר קרה לכם שמדד ה -Page Life Expectancy צנח פלאות והגיע למצב שתוחלת החיים של כל Page היא שוות ערך לתוחלת החיים הממוצעת של אזרח באחת המדינות ביבשת אפריקה?? הפעם לשם שינוי הפעם לא אכתוב על נושא תיאורטי אלא אציג בעיה שנתקלתי בה בזמן עבודתי אצל אחד הלקוחות שלנו הקשורה למדד זה.</p>
<p>שבוע שעבר התקבלה התראה במערכת שמדד בשם Page Life Expectancy צנח אל מתחת ל- 250 שניות בממוצע. הערך התקין של מדד זה לפי המלצות מיקרוסופט הוא כ- 300 שניות.  למי שלא מכיר מדד זה מציין למעשה את הזמן הממוצע שדף (Page) חי ב- Buffer Pool של SQL Server  לפני שהוא נמחק משם. נעצור לרגע ונסביר, פעולות I/O יכולות להיות כבדות, ארוכות זמן וגם לגזול משאבים רבים מהשרת. לכן, SQL Server משתמש ב- Buffer Pool כפתרון המרכזי על מנת להקל על השרת, לצמצם את זמן אחזור המידע והבאתו את הלקוח (בין אם זה משתמש כגון DBA או אפליקציה).ה- Buffer Management מורכב משני מנגנונים מרכזיים: הראשון הוא: Buffer Manager שתפקידו לעדכן בפועל את הדפים (הסבר עוד מעט&#8230;). ואילו המנגנון השני הוא ה- Buffer Pool אשר שומר בתוכו דפים בגודל 8 KB, אלו יכולים להיות Data Pages או Index Pages.למעשה ה- Buffer Manager קורא דפים ומכניס אותם אל תוך ה- Buffer Pool ובסיום התהליך הוא גם אחראי על כתיבת השינויים אל הדיסק עצמו. למעשה, דף יישאר בתוך ה- Buffer Pool עד לנקודה בזמן שה- Buffer Manager יצטרך מקום על מנת להעלות דפים אחרים שלא נמצאים בתוך ה- Buffer Pool. כאשר כמובן דף שנקרא וכבר נמצא ב- Buffer Pool ייכתב בחזרה אל הדיסק רק אם הוא עבר שינוי כלשהו. נקודה חשובה נוספת, דף יחיד יכול לעבור מספר שינויים לפני שהוא נכתב לדיסק! לדוגמא: דף מטבלה מסוימת נקרא ונמצא ב- Buffer Pool למשך עשר דקות, כאשר בעשר הדקות הללו הוא עבר חמישה שינויים, ואז לאחר 5 דקות, ה- Buffer Manager נאלץ להוציא אותו מתוך ה- Buffer Pool משום שעליו להכניס דפים חדשים אל ה- Buffer Pool וזאת משום שאין מספיק מקום ב- Buffer Pool להכיל את הדפים שהוא צריך להשתמש בהם.  מה שמוביל לי לנקודה הבאה, איך נוכל לדעת מה גודלו של – Buffer Pool  וע&quot;פ מה הוא נקבע.  כאשר SQL Server עולה, הוא מחשב את גודלו של ה Buffer Pool. כאשר הוא מתבסס על מספר פרמטרים שונים, כמו כמות ה- Physical Memory  על השרת, הגדרת המספר המקסימלי של Server Threads וכו'. על מנת לדעת מה גודלו של ה-Buffer Pool  שלכם, פשוט הריצו את השאילתה הבאה:</p>
<p style="direction: ltr"><span style="color: #0000ff">SELECT </span>* <span style="color: #0000ff">FROM </span><span style="color: #008000">sys.dm_os_sys_info</span></p>
<p>כאשר אנו מחפשים את הערכים תחת העמודות:</p>
<ul>
<li><strong>bpool_commited</strong> &#8211; מייצג את הגודל בפועל של ה- Buffer Pool. הערכים בתוך העמודה הם למעשה מספר ה- Pages שקיימים בתוך ה- Buffer Pool.</li>
<li><strong>bpool_commit_target</strong> &#8211; מציין את גודל היעד הרצוי של ה- Buffer Pool, (גם כאן המספר מייצג את מספר הדפים). במקרים בהם ה- bpool_commit_target גדול מ- bpool_committed אזי, SQL Server ינסה תמיד להשיג עוד זיכרון ל-bpool_committed, ולהגיע למצב של שיוון ביניהם.</li>
</ul>
<p>לאחר הסבר זה, אני מקווה שנוכל להבין בצורה טובה יותר, מהי המשמעות המעשית כאשר אנו מקבלים התראה שמדד ה- Page Life Expectancy צונח אל הקרקעית, ומגיע לערך של שניות בודדות. המשמעות המעשית היא, שה- Buffer Manager מעלה אל הזיכרון כמות גדולה מאד של דפים, שכל הנראה אין בכך צורך. וכאשר מדד זה צונח בצורה חדה כל כך ופתאומית, עולה השאלה, מה נשתנה יום מיומיים??? מה קרה היום שלא היה אתמול?? במקרה שלא מקבלים תשובה ברורה ומדויקת, שעשויה לסייע לנו, נאלץ לצלול עמוק אל תוך ה- Buffer Pool  על מנת לראות אילו דפים הוא מחזיק בתוכו, או  בלשון מדויקת יותר,  מאיזו טבלה או אינדקס מגיעים הדפים אל ה- Buffer Pool  והאם הם שייכים אל טבלה מרכזית אחת? או ממספר מצומצם של טבלאות??</p>
<p>לשם כך נעזרתי בשאילתה הבאה שחיבר גיא גלנצר  (<a href="http://www.madeira.co.il/buffer-pool-distribution-by-tables/" target="_blank"><span style="color: #0000ff">לחצו על הקישור להורדה</span></a>), שאילתה זו מציגה אינפורמציה יעילה מאד לפתרון בעיות אשר קשורות ל- Buffer Pool. בשאילתה למעשה יש חיבור בין כמה DMV's שונים כאשר המרכזי שבהם הוא <span style="color: #008000">sys.dm_os_buffer_descriptors</span>, והתוצאה הסופית היא הצגה של שם הסכמה, שם הטבלה, כמה KB מהטבלה נמצאים בתוך ה- Buffer Pool כרגע, מה גודל הטבלה על הדיסק, וכמה אחוזים מן הטבלה נמצאים בתוך ה- Buffer Pool.</p>
<p>לאחר הרצה של השאילתה הזו, הבחנתי ש- 75% מה- Buffer Pool נתפסים ע&quot;י שתי טבלאות מרכזיות. עובדה נוספת שצדה את עיניי שמספר ה-KB של שתי הטבלאות החשודות עולה ויורד ובאופן מתמיד. כלומר בכל רגע נתון הן תופסות בין 65% ל- 75% אחוז מגודלו של ה- Buffer Pool.</p>
<p><strong>מה יכולות להיות הסיבות לכך??</strong></p>
<p>כאשר מחפשים ברשת מידע הקשור לבעיות הקשורות למדד Page Life Expectancy בד&quot;כ נקרא שיש לנו בעיות זיכרון, ויש להוסיף זיכרון לשרת! יחידי סגולה מעלים את האפשרות שהבעיה היא <strong><span style="text-decoration: underline">לא</span></strong> בזיכרון אלא בשאילתות גרועות או היעדר אינדקסים (זה המקום להעיר כי אם אכן הבעיה נובעת משאילתות גרועות, אז לא תעזור כמות הזיכרון שנוסיף אל השרת, משום שסביר מאד להניח שאת הזיכרון שהוספנו יישתו בצימאון עד דלא ידע, אותן השאילתות הגרועות!).</p>
<p><strong>לכן מצאתי לנכון ציין את הגורמים האפשריים לצניחת מדד ה- Page Life Expectancy הם:</strong></p>
<ol>
<li><strong>שאילתות גרועות והיעדר אינדקסים</strong>- לשאילתות גרועות יכולות להיות השפעה הרת גורל על מדד זה. כאשר אני מדבר על שאילתות גרועות אני מדבר על אלו שצורכות הרבה מאד משאבים, בדגש על Physical I/O. כמובן במקרים רבים שאילתות בעייתיות נקשרות להיעדר אינדקסים ( או אינדקסים יעילים), עובדה אשר גורמת לפעולות Table Scan שממנה אנו צריכים להיזהר כמו מאש במיוחד כאשר עוסקים בטבלאות גדולות. מקרים אחרים בהם שאילתות יבצעו כמות מוגזמת של Physical I/O, קשורים בדרך כלל לחיבור בין טבלאות בעזרת JOIN. גורם נוסף הוא שימוש באופרטור ORDER BY, בדגש על מקרים בהם המידע לא נשמר בטבלאות בצורה ממוינת.</li>
<li><strong>השתנות ה- </strong><strong>Data</strong><strong>-</strong> לרוב ניתן לאפיין את ה- Data שלנו בצורה מסוימת, יש לו תבנית אשר לא משתנה בצורה קיצונית. אבל עיתים ישנם מקרים בהם טבלה מסוימת שהייתה רגילה להיות קטנה, הולכת ותופחת ומגיעה לגדלים עצומים ביחס למה שהיא רגילה להיות, עובדה זו, גם יכולה לגרור פגיעה ישירה במדד ה- Page Life Expectancy. במיוחד אם מדובר על טבלה שפונים אליה באופן תדיר.</li>
<li><strong>בעיות חומרה-</strong> לפני שהולכים ובודקים את השאילתות יש לבדוק האם משהו השתנה בכל הקשור לחומרה, משום שישנם מצבים בהם אחד מה- Slots שבהם יושב הזיכרון נהרס' וcמקרים הללו גם אם נשפר מאד את השאילתות שלנו, לא נרגיש שינוי בביצועים משום שבעיה היא בכלל חומרתית.</li>
</ol>
<p>במקרה הספציפי שלי הבעיה הייתה כפולה מחד' טבלה אחת גדלה בצורה קיצונית בעקבות תקלה שהייתה במערכת. ומאידך מסתבר שיש גם שתי שאילתות שעברו שינוי ושהן מורצות באופן תדיר, ולכן רוב ב- Buffer Pool מאוכלס ע&quot;י מידע שמגיע משאילתות אלו.</p>
<p>לכן נקטתי את הפעולות הבאות:</p>
<p><strong>1.</strong><strong>שלב א'- מחיקה-</strong> מחיקת הנתונים שהצטברו בעקבות התקלה. טבלה שאמורה להכיל בשיא הכושר שלה כ- 500 אלף שורות, הגיעה למצב קיצוני שהיא מכילה כמעט 11 מליון שורות. יש לציין שפונים אל טבלה זו באופן תדיר, ולכן למחיקה הייתה השפעה על מדד ה- Page Life Expectancy אך לא דרסטית.</p>
<p>2.<strong>שלב ב' תיקון השאילתות- </strong>על מנת לאתר את אותן השאילתות הבעייתיות נעזרתי בשני כלים שונים- הראשון הוא SQL Profiler, אשר באמצעותו יכולתי להקליט ולייצר קובץ Trace. ואז לנתח אותו ולהגיע למסקנות ברורות ונקודתיות, היכן בדיוק נמצאת הבעיה. כלי נוסף ויעיל לא פחות הוא  <span style="color: #008000">sys.sysprocesses</span> זהו  VIEW מגרסאות ישנות של SQL Server. כיום, בגרסאות חדשות יותר ניתן לעבוד עם ה- DVM's הבאים: <span style="color: #008000">sys.dm_exec_sessions</span> או <span style="color: #008000">sys.dm_exec_requests</span> שמיכלים מידע על אילו תהליכים רצים כרגע על השרת ומי מריץ אותם (הערה חשובה: ניתן להשתמש ב- <span style="color: #999999">CROSS APPLY</span> ל- <span style="color: #008000">sys.dm_exec_sql_text</span><strong> </strong>ולהוציא משם את הטקסט שאותו Process  מריץ). לאחר שמצאתי את אותן השאילתות החשודות, נחשו לאילו טבלאות הן פונות??? יפה!!!! הן פונות בדיוק אל אותן שתי טבלאות שמחזיקות 75% מה- Buffer Pool.  לאחר מספר בדיקות מצאתי כי שאילתה אחת ניתן לשפר בעזרת Sub Query. מסתבר שאם מורידים JOIN אחד ובמקומו מוסיפים בתוך ה-  WHERE  Sub Query שמחזיר רשימה של ערך שיש עליו אינקסים טובים.אז זמן הריצה של השאילתה יורד מדקה (ואף יותר) למספר שניות בודדות וכמובן שכמות ה<strong>- </strong>Physical I/O ירדה פלאים, ממאות אלפים למספר בודד של אלפים. את השאילתה השנייה, היה קצת יותר קשה לשפר, משום שלא יכולתי להשתמש ב- Sub Query. ולכן מכיוון שהשאילתה ביצעה JOIN בין 3 טבלאות שונות (שתיים מהן גדולות מאד), ורוב המידע נלקח מטבלה אחת ואז מוצלב עם יתר הטבלאות, החלטתי להשתמש בתחנת ביניים בצורת טבלה זמנית, אשר מכילה את המידע הרלוונטי בלבד, ועכשיו במקום לבצע JOIN  בין שתי טבלאות גדולות מאד, יש לנו JOIN בין טבלה זמנית קטנה מאד לבין טבלה גדולה, ואת זה הרבה יותר קל ל- SQL Server  לבצע. כמו כן, על מנת לייעל את השאילה עוד יותר, הוספתי אינדקס מתאים לאחת הטבלאות הגדולות וגם כאן השיפור היה עצום, השאילתה המקורית רצה בין דקה לשתי דקות, ואילו לאחר השיפור זמן הריצה שלה היה בין 0 ל- 3 שניות בלבד! Physical I/O צנח אל כ- 10,000.</p>
<p>לאחר כל זאת, כל שנותר לי לעשות הוא שני דברים, הראשון להתקשר לגיא גלנצר וצחי חקיקת ולהודות להם על העזרה הרבה שהעניקו לי, במיוחד על הכלים לפתרון בעיה מסוג זה! הדבר השני, היה להרים רגליים על השולחן, ולצפות בגרף של מדד ה- Page Life Expectancy דרך ה- Perfmon, נוסק אל על ומתייצב על רמה של  כ- 2000 שניות.</p>
<p>מקווה שנהניתם לקרוא,</p>
<p>חקיקת יוסי<strong></strong></p>
</div>]]></content:encoded>			<wfw:commentRss>http://www.madeira.co.il/case-study-page-life-expectancy-counter/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>&#8235;High Availability- Chapter 1&#8236;</title>		<link>http://www.madeira.co.il/high-availability-chapter-1/</link>
		<comments>http://www.madeira.co.il/high-availability-chapter-1/#comments</comments>
		<pubDate>Tue, 21 Feb 2012 07:37:44 +0000</pubDate>
		<dc:creator>&#8235;יוסי חקיקת&#8236;</dc:creator>				<category><![CDATA[בלוגים]]></category>
		<category><![CDATA[כללי]]></category>
		<category><![CDATA[מקודמות]]></category>

		<guid isPermaLink="false">http://www.madeira.co.il/?p=4333</guid>
		<description><![CDATA[&#8235;מאז פיגועי הטרור במגדלי התאומים ב-11 לספטמבר עלתה המודעות לזמינות גבוהה של נתונים. ישנן שיטות רבות להשיג זמינות גבוהה. פוסט זה הוא פרק מראשון מתוך שניים בנושא. הפעם אתמקד בשתי שיטות: Failover Clustering ו-  Log Shipping.&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p><img src='http://www.madeira.co.il/wp-content/plugins/simple-post-thumbnails/timthumb.php?src=/wp-content/thumbnails/4333.jpg&amp;w=214&amp;h=129&amp;zc=1&amp;ft=jpg' alt='post thumbnail' /></p>
<p>זה קרה ביום שלישי בבוקר (שעון ארה&quot;ב), בשעה 08:46 פגע המטוס הראשון במגדל הצפוני, כ-17 דקות מאוחר יותר, בשעה 09:03 פגע המטוס השני במגדל הדרומי מהשעה 10:28 באותו בוקר, לא נשאר זכר ממגדלי התאומים עליהם השלום. אירוע מכונן זה גרם למהפכה בתחומים רבים, אחד מהם, הוא הנושא שעליו אכתוב בפוסט זה- High Availability. ארגונים רבים איבדו את כל המידע שלהם בפיגועי ה- 11 בספטמבר, אמנם מדובר על אירוע שניתן לקטלג אותו תחת <a href="http://www.simple-talk.com/sql/backup-and-recovery/disaster-recovery-for-sql-server-databases-/">DRP</a>, ראשי תיבות ל: Disaster Recovery Plan , שקשור יותר לביצוע גיבויים, שמירתם ושחזורם על שרת אחר במידת הצורך, אך בהחלט ניתן לומר שלאירוע הייתה השפעה רחבה יותר, הוא העלה על נס גם את נושא הזמינות הגבוהה של הנתונים, גם במקרים של כשלים קצת פחות קריטיים ממטוס או שניים שנכנסים אל הבניין שבו את/ה עובד/ת.</p>
<p>היום אתחיל בסדרה של שני פוסטים שכל פוסט אקדיש לשיטות אחרות של High Availability. כאשר מדברים על זמינות גבוהה צריך לקחת בחשבון את כל הגורמים אשר עלולים להינזק במידה כזו או אחרת, ושכתוצאה מכשל זה תיפגע זמינות הנתונים. דוגמאות לרכיבים מועדים לפורענות: דיסקים, שרתים, SQL Server, כבלים, חשמל, מערכת ההפעלה, שאילתות גרועות, נעילות ועוד ועוד. לכן, כאשר באים ליישם פתרון של זמינות גבוהה, יש לשים לב לאילו מהכשלים שצוינו הוא נותן מענה ולאילו לא! לא חסרים מזיקים, ושאר מרעין בשין, וחלילה שלא נטעה לחשוב שפתרון מסוים שבחרנו עונה בצורה מושלמת על כל הכשלים הבאים עלינו לכלותינו.</p>
<p><strong>שיטה מספר 1 : Failover Clustering</strong></p>
<p>זהו פתרון ברמת השרת, מבחינת SQL Server הוא פועל ברמת ה- Instance. יש להגדיש כי פתרון זה איננו פתרון SQL טהור, למעשה מדובר על פתרון ברמת מערכת ההפעלה (ארגונים רבים משתמשים בו בחוכמה ורותמים אותו לשרתי ה- SQL Server). ל- Windows Server  יש רכיב שמאפשר לו ליצור Cluster.כמו כן, יש להגדיר את Cluster  גם ברמת ה- SQL או בעת ההתקנה או לאחר מכן. כלומר, לוקחים שני שרתים או יותר (המונח המקובל הוא Node), ומקצים להם משאבים משותפים (לדוגמא Disk Space), שכל אחד מן השרתים יכול להשתמש בהם, <span style="text-decoration: underline">אבל</span> לא בבת אחת, אלא כל פעם המשאבים יהיו זמינים אך ורק ולשרת אחד. מכאן גם נובעים השמות של השרתים, השרת שצורך ברגע נתון את המשאבים נקרא Active ואילו השרת/ים האחרים נקרא/ים Passive. לשם המחשה, נניח שיש לנו שני שרתים שמחוברים יחדיו ב- Cluster. בן לאדן החליט לשלוח מטוס צעצוע עמוס חומרי נפץ אל שרת ה- Active, ברגע הפיצוץ מתבצע Failover אוטומטי, והשרת שהיה בתפקיד Passive הופך להיות Active. נקודה חשובה, יש לדאוג שכל השרתים יהיו זהים לחלוטין מבחינת המפרט הטכני שלהם. הסיבה הראשונה נעוצה בביצועים, אם שרת אחד יהיה חזק מאד ואחר יהיה חלש, אז ברגע שיתבצע Failover אל השרת החלש הוא פשוט לא יוכל לעמוד בעומס ונרגיש פגיעה בביצועים במקרה הטוב ומקרה הרע אף נגרום לקריסתו של השרת החלש. הסיבה השנייה קשורה לדרישות של חברת מיקרוסופט, שדורשת שהשרתים יהיו זהים, אחרת הם לא יעניקו שום תמיכה במקרה של תקלה.</p>
<p><strong>יתרונות: </strong></p>
<p><strong>מקל על </strong><strong>maintenance</strong><strong>-</strong> ניתן לבצע ביתר קלות פעולות תחזוקה שוטפות ברמת השרת או SQL Server כגון התקנה של Service pack או עדכון גרסא, כמעט ללא פגיעה בפעילות השוטפת. וזאת משום שאני יכול לפעול בצורה הבאה: להתקין Service pack על השרת ה- Passive, לאחר סיום ההתקנה, לבצע Failover בצורה יזומה וידנית בין השרתים, ואז להתקין את אותו ה- Service pack על השרת השני ומיד לאחר מכן שוב לבצע Failover ידני על מנת להחזיר את השרתים לתפקוד המקורי שלהם. למותר לציין, כי בכל זמן התחזוקה, המערכת נמצאת באוויר וזמינה לכל דורש.<br />
<strong>Failover</strong><strong> אוטומטי ומהיר-</strong> במקרה של תקלה המעבר בין השרתים הוא מהיר מאד, למעשה פרק הזמן שלוקח ל- SQL Server לעלות, הוא פרק הזמן שהשרת לא יהיה זמין כלל, לרוב מדובר על כשישים שניות בלבד ואף פחות מכך. יתר על כן, המשתמשים כמעט ולא ירגישו שבוצעה מעבר בין השרתים, מבחינתם הם ממשכים לפנות לאותה כתובת IP, לאותו שרת והם ממשיכים לקבל את אותו השירות.</p>
<p><strong>פתרון ברמת השרת-</strong> במקרה של תקלה שקשורה לשרת עצמו, מכל סיבה שלא תהיה, אנו יכולים להיות רגועים ולדעת שיש לנו שרת גיבוי שיהפוך במהירות להיות השרת הפעיל ללא דיחוי וללא שום התעסקות עם העברה או השלמה של נתונים חסרים כתוצאה מהכשל.</p>
<p><strong>חסרונות: </strong></p>
<p><strong>מגבלת מקום-</strong> השרתים צריכים להיות באותו LAN הם צריכים להיות מחוברים פיזית אל אותם המשאבים. זוהי נקודת חולשה משמעותית, אם קרתה תקלה כלשהי שפגעה במבנה הפיזי בו יושבים שני השרתים, סביר להניח ששניהם יפגעו ואז המידע לא יהיה זמין כלל. (אם כי בתחום זה, גרסת 2012 הבאה עלינו לטובה, מביאה פתרון שבעזרתו נוכל לבצע פתרון Cluster גם ברשת WAN).</p>
<p><strong>יקר-</strong> מצריך קנייה של דיסק שיכול להתחבר לשני שרתים שונים, לא מדובר כאן על קנייה של שרת סטנדרטי. ובנוסף על מנת ליישמו חייבים להחזיק שני שרתים לפחות, רישיונות וכו'.</p>
<p><strong>המידע יושב במקום אחד בלבד–</strong> החיסרון אולי הגדול ביותר של שיטה זו הוא שעדיין יש לנו Single Point Of Failure, כלומר, אם לדוגמא יש כשל מסוים בדיסקים, אז לא תעזור לנו העובדה שיש לנו שני שרתים, משום הדיסקים הם משאב משותף לשני השרתים. המידע לא עובר לשום מקום אחר, הוא יושב במקום אחד בלבד, וזה סיכון דיי גדול.</p>
<p><strong>שיטה מספר 2 : Log Shipping</strong></p>
<p>טכנולוגיה זו מגיעה Build-in  עם SQL Server והיא עובדת ברמה של <span style="text-decoration: underline">מסד נתונים</span>. שמה של טכנולוגיה מעידה על מהותה בצורה הטובה ביותר. מדובר בעצם על שני מסדים נתונים זהים שיושבים שני שרתים שונים (ללא הגבלת מרחק), כאשר כל מה שצריך זה לבצע גיבוי של קובץ הלוג באופן תדיר ולשלוח אותו לשרת המרוחק. להן פירוט השלבים ליישום שיטה זו:</p>
<ul>
<li>1.גיבוי Full של מסד הנתונים</li>
<li>2. שיחזור של אותו גיבוי על שרת מרוחק, יש לשים לב שאנו משחזרים את מסד הנתונים במצב של No Recovery.</li>
<li>3. מעתה ואילך יתבצעו באופן תדיר שתי הפעולות הבאות: הראשונה גיבוי של קובץ הלוג במסד הנתונים בסביבת ה- Production. גיבוי תדיר של קובץ הלוג יתרום משמעותית  להקטנת זמן המעבר משרת ה- Production לשרת הגיבוי במצב של תקלה. הפעולה השנייה, היא כאמור שיחזור של קובץ הלוג בשרת המרוחק גם כן במצב של No Recovery.</li>
</ul>
<p>מאחורי הקלעים, נוצרים למעשה שלושה Jobs אשר מבצעים את העבודה עבורנו. Job אחד דואג לבצע גיבוי של קבץ הלוג, Job שני דואג להעתיק את הקבצים אל שרת הגיבוי המרוחק, ואילו ה- Job השלישי לוקח את קבצי הגיבוי ועושה להם שיחזור במצב של No Recovery.</p>
<p><strong>יתרונות</strong>:</p>
<p><strong>גיבוי מלא של  הנתונים-</strong> למעשה בשיטה זו בניגוד לשיטה הקודמת יש לנו העתק מלא של מסד הנתונים על שרת מרוחק, ובמקרה של נזק לדיסק עצמו, אנו יכולים להיות רגועים.</p>
<p><strong>ניתן ליישם את שיטה זו על מספר שרתים במקביל-</strong> מי שאינו רגוע שהמידע שלו מגובה רק במקום אחד בלבד, יכול ליישם את שיטה זו על מספר שרתי גיבוי במקביל, וכך להבטיח לעצמו כפילות של המידע ומשנה בטיחות למקרה של תקלה בשני השרתים בד בבד. יתר על כן, ניתן להוסיף שבשיטה זו אין שום מגבלות של מרחק, וניתן להציב את שרת הגיבוי בכל מקום אשר נחפוץ.</p>
<p><strong>ניתן להשתמש בשרת הגיבוי כשרת לדוחות-</strong> מכיוון שאין כמעט פעילות על שרת הגיבוי, ניתן לנצל אותו כשרת שעליו מריצים דוחות כבדים, וכך נקל מהעומס על סביבת ה- Productuon.</p>
<p><strong>חסרונות</strong>:</p>
<p><strong>זמן</strong>- בשיטה זו לוקח זמן רב מדיי עד שנוכל להגיע למצב שבו המערכת באוויר. הסיבה לכך נעוצה בעובדה שישנן יותר מדיי פעולות לבצע על שנוכל להביא את שרת הגיבוי למצב זמין. הפעולות הן: גיבוי של קובץ הלוג האחרון לפני הקריסה, שליחה ברשת של אותו קובץ אל שרת הגיבוי המרוחק, שיחזור של קובץ הלוג האחרון במצב With Recovery. כמו העובדה שאין Failover אוטומטי, מאיטה את התהליך אף היא.</p>
<p><strong>מסד הנתונים לא זמין בשרת הגיבוי</strong>-  מכיוון שאנו תמיד נמצאים במצב של Restoring, מסד הנתונים שלנו לא זמין כלל.</p>
<p><strong>אין </strong><strong>Failover</strong><strong> אוטומטי</strong>-  אנו צריכים לדאוג לבצע את כל הפעולות בצורה ידנית בכל שעה שנדרש.</p>
<p><strong>עומס על המערכת-</strong> שיטה זו שמצריכה גיבוי תדיר של קבצי הלוג ושליחה שלהם, גורמת להכבדה מסוימת על שרת ה- Production.</p>
<p>בפוסט זה הצגתי שתי שיטות ל- High Availability. בפעם הבאה אסקור עוד שתי שיטות נוספות, ואבצע סיכום של שני הפוסטים, וכמו כן אביא המלצות מתי נבחר להשתמש בכל שיטה.</p>
<p>מקווה שנהניתם לקרוא,</p>
<p>חקיקת יוסי</p>
</div>]]></content:encoded>			<wfw:commentRss>http://www.madeira.co.il/high-availability-chapter-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>&#8235;* Select&#8236;</title>		<link>http://www.madeira.co.il/select/</link>
		<comments>http://www.madeira.co.il/select/#comments</comments>
		<pubDate>Sun, 05 Feb 2012 17:46:26 +0000</pubDate>
		<dc:creator>&#8235;יוסי חקיקת&#8236;</dc:creator>				<category><![CDATA[בלוגים]]></category>
		<category><![CDATA[כללי]]></category>
		<category><![CDATA[מקודמות]]></category>
		<category><![CDATA[Performance Tuning]]></category>
		<category><![CDATA[שיפור ביצועים]]></category>

		<guid isPermaLink="false">http://www.madeira.co.il/?p=4121</guid>
		<description><![CDATA[&#8235;במקרים רבים בחיינו אנו כבר רגילים להיזהר מהכוכבית. במודעות פרסום, בחוזים, הסכמים שונים, פרסומות בטלוויזיה, והחל מהיום (אם לא ידעתם...) גם בכל הקשור לסביבת ה- Production של SQL Server. לשימוש ב- * Select ישנן השפעות שלילות לא מעטות וחלקן יכולות להיות משמעותיות ביותר. נכון שמסקרן אתכם לדעת?? כנסו לפוסט....&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p><img src='http://www.madeira.co.il/wp-content/plugins/simple-post-thumbnails/timthumb.php?src=/wp-content/thumbnails/4121.jpg&amp;w=214&amp;h=129&amp;zc=1&amp;ft=jpg' alt='post thumbnail' /></p>
<p>SELECT *</p>
<p>מכירים את זה שאתם מגיעים לחתום על חוזה התקשרות עם חברה מסוימת, התנאים נראים מבטיחים, הצעה מעולה, ממש עסקת חייכם, אבל אז מגיעים לסוף הדף, ושם באותיות טל ומטר יש כוכבית, או כמה אשר מבהירות לכם שלא מדובר בעסקת חייכם ולא נעליים. היום כל בר דעת יודע- יש להיזהר מהכוכבית!! אז מעתה והלאה, אני מציע לכם בחום, ליישם את הלקח הזה גם בכל הקשור לסביבת ה- Production של SQLServer!! בסביבה זו יש להימנע ככל האפשר מהשימוש ב- *.</p>
<p>אחרי שבפעם האחרונה עסקתי בהרגל מגונה שעיקרו הוספת<span style="color: #0000ff"> </span><span style="color: #0000ff"><a href="http://www.madeira.co.il/nolock/" target="_blank"><span style="color: #0000ff">NOLOCK</span></a> <span style="color: #333333">לכל שאילתה בלי חשבון</span>,</span> היום אעסוק בהרגל מגונה אחר, נפוץ הרבה יותר, והוא כאמור * <span style="color: #0000ff">SELECT </span>. בפוסט זה אתייחס לנושא ממספר זוויות והן: הסיבה העיקרית לשימוש ב- *, מתי השימוש לא מזיק, ועיקר הפוסט, ההשפעות השליליות של * <span style="color: #0000ff">SELECT </span>, כן, יש כאלו, ולא מעט!</p>
<p>כאשר מנסים להצדיק את השימוש ב- * <span style="color: #0000ff">SELECT</span> הטענה הראשונה וכמעט היחידה שעולה היא ש- * <span style="color: #0000ff">SELECT </span>חוסך עבודה. נגיד שיש טבלה עם 5 עמודות, ומחר  צריך להוסיף עמודה נוספת, אז לא צריך לשנות את הקוד יותר מדיי, משום ש &#8211; * <span style="color: #0000ff">SELECT </span> לוקח את כל העמודות וזה חוסך זמן, אין צורך לתקן את הקוד ע&quot;י הוספת העמודות. הטענה השנייה היא דומה, אם ישנן הרבה עמודות בטבלה מסוימת אז זה יותר קל ונוח לרשום * במקום להקליד את כל העמודות. הצד השווה בין שתי הטענות הוא ששורש השימוש ב- * טמון בעצלנות (או חסכון בזמן אם להיות עדינים יותר&#8230;) אז אם אלו הסיבות העיקריות לשימוש ב- *,מסתבר שלא צריך לעבוד קשה מדיי על מנת להציג את כל העמודות של טבלה מסוימת. למי שלא מכיר ישנה אפשרות ב- Management Studio להוסיף את כל העמודות בהינף קליק. ב- Object Explorer, לכל טבלה מופיעות אותן שש עמודות קבועות, אחת מהן היא Columns. עומדים על תיקייה בשם  Columns ופשוט גוררים אותה אל המיקום הרצוי בחלון ה- Query. וזהו! לא צריך להקליד כלום, כל העמודות כתובות לפניכם, מופרדות בפסיקים על מגש של Query.</p>
<p>אז לאחר שהסיבות העיקריות לשימוש ב * <span style="color: #0000ff">SELECT <span style="color: #333333">כבר לא קיימות</span></span>, אדגיש כי במקרים לא מעטים השימוש ב * <span style="color: #0000ff">SELECT</span> הוא בסדר גמור ולגיטימי, לדוגמא כאשר רוצים לבצע בדיקות מסוימות או שעובדים עם DMV's שונים. אין שום בעיה במקרים אלו. הבעיות מתחילות שעושים שימוש ב * <span style="color: #0000ff">SELECT </span>בסביבת ה- Production, לדוגמא: * <span style="color: #0000ff">SELECT</span> בפרוצדורות שונות. מה שמוביל אותי לדבר על הצד הפחות זוהר של * <span style="color: #0000ff">SELECT </span>.</p>
<div id="attachment_4185" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.madeira.co.il/wp-content/uploads/2012/02/Table31.png" rel="wp-prettyPhoto[g4121]"><img class="size-medium wp-image-4185" src="http://www.madeira.co.il/wp-content/uploads/2012/02/Table31-300x143.png" alt="" width="300" height="143" /></a><p class="wp-caption-text">לחץ על התמונה להגדלה</p></div>
<p><span style="text-decoration: underline">ההשפעות השליליות של * <span style="color: #0000ff">SELECT :</span></span></p>
<ul>
<li><strong>פגיעה בשימוש נכון באינדקסים קימיים</strong>- במקרים מסוימים כאשר נריץ שאילתה עם * <span style="color: #0000ff">SELECT </span>, התוצאה הישירה תהיה סריקה מלאה של טבלה או של ה- Clustered Index.  לשם המחשה נריץ את שתי השאילתות הבאות, שימו לב השאילתות זהות במהותן, רק שבראשונה יש שימוש ב- *, ואילו בשנייה כתובות העמודות הרצויות בלבד:</li>
</ul>
<p style="text-align: left"><span style="color: #008000"> :Using SELECT * query &#8211;</span></p>
<p style="text-align: left"><span style="color: #808080">*</span> <span style="color: #0000ff">SELECT</span></p>
<p style="text-align: left"><span style="color: #0000ff">FROM </span>Sales.SalesOrderDetail</p>
<p style="text-align: left"><span style="color: #0000ff">;WHERE</span> ProductID <span style="color: #808080">&lt;</span> 750</p>
<p style="text-align: left"><span style="color: #008000">:Same query as the above but this time, using specific columns &#8211;</span></p>
<p style="text-align: left"><span style="color: #0000ff">SELECT </span>SalesOrderDetailID,ProductID,SalesOrderID</p>
<p style="text-align: left"><span style="color: #0000ff">FROM </span>Sales.SalesOrderDeta</p>
<p style="text-align: left"><span style="color: #0000ff">;WHERE </span>ProductID<span style="color: #808080"> &lt;</span> 750</p>
<p style="text-align: right">נציץ ב- Execution plan:</p>
<p style="text-align: right">
<div id="attachment_4140" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.madeira.co.il/wp-content/uploads/2012/02/ExecutionPlan1.png" rel="wp-prettyPhoto[g4121]"><img class="size-medium wp-image-4140 " src="http://www.madeira.co.il/wp-content/uploads/2012/02/ExecutionPlan1-300x116.png" alt="" width="300" height="116" /></a><p class="wp-caption-text">לחץ להגדלת התמונה</p></div>
<p style="text-align: right">השאילתה הראשונה (עם * ), עולה כמעט פי 50 מהשאילתה שמציינת במפורש שדות ספציפיים. הסיבה לכך נעוצה בעובדה ששאילתה מספר 1 גורמת לסריקה מלאה של ה- Clustered Index ( שווה ערך פחות או יותר סריקה מלאה של הטבלה). ואילו בשאילתה מספר 2 בוצעה סריקה של ה- NonClustered Index שבמקרה זה, היא פעולה הרבה פחות כבדה. זאת ועוד, במקרים אחרים, שימוש ב- * <span style="color: #0000ff">SELECT </span> גורר פעולות מיותרות אחרות(וכבדות!!) כמו Lookups. לדוגמא אם נריץ את אותן שאילתות מהדוגמא הקודמת אך נשנה את התנאי ב- WHERE ל-  20 אז נוכל לראות ששאילתה מספר 1 גורמת לפעולת lookups שהיא בעצם החלק הכבד של השאילתה (50% מעלות השאילתה מוקדשת לכך). ואילו באפשרות השנייה, מתבצע Index seek על NonClustered IX_SalesOrderDetail_ProductID, שהיא יעילה בהרבה.</p>
<p style="text-align: right">
<div id="attachment_4143" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.madeira.co.il/wp-content/uploads/2012/02/ExecutionPlanWithWhere20.png" rel="wp-prettyPhoto[g4121]"><img class="size-medium wp-image-4143" src="http://www.madeira.co.il/wp-content/uploads/2012/02/ExecutionPlanWithWhere20-300x135.png" alt="" width="300" height="135" /></a><p class="wp-caption-text">לחץ על התמונה להגדלה</p></div>
<ul style="text-align: right">
<li><strong>יצירת עומס על השרת</strong>- אז כפי שהרגע ראינו במקרים רבים שימוש ב * <span style="color: #0000ff">SELECT </span>גורם לסריקות של טבלאות או אינדקסים בצורה לא יעילה ולא נחוצה. ישנם מקרים רבים בהם השאילתה מחזירה לאפליקציה נתונים שאין בהם שום שימוש, משום שהשאילתה מחזירה 10 עמודות לדוגמא, אך האפליקציה מציגה רק 3 עמודות מתוך ה- 10. העומס מתבטא הן בפעולות I/O רבות שאיו בהן צורך, והן במעבר של נתונים ברשת שגם בהם כמובן אין שום שימוש.</li>
<li><strong>שינוי סכמה ב- </strong><strong>View</strong>-  כאשר יוצרים View בעזרת * <span style="color: #0000ff">SELECT </span> ישנה בעיה עיקרית אחת. נניח שלאחר זמן מה, מחליטים לשנות את שם אחת העמודות מ- Bla ל- Bla2. ה-MetaDta של ה- View לא מתעדכן באופן אוטומטי על השינוי, ואין לו מושג שעמודה מסוימת כבר לא נקראת כפי שהיא נקראה בעבר. נסבך את העניינים עוד טיפה, תארו לכם שעכשיו נוסיף עמודה חדשה שנקראת Bla והיא בכלל מסוג אחר(עמודת תאריך במקום מספר שהיה עד כה) במצב זה אנו נקבל ונציג מידע שגוי. (אציין כי ניתן למנוע מצב זה בעזרת שימוש ב- SCHEMABINDING אשר לא מאפשר שימוש ב- * <span style="color: #0000ff">SELECT</span>).</li>
<li><strong>· </strong><strong>ניטור שגיאות- </strong> על מנת להמחיש את הנקודה הבאה אגש ישר לדוגמא, ישנה פרוצדורה שמקבלת כפרמטר את rowguid@  ומחזירה נתונים: <strong> </strong></li>
</ul>
<p style="text-align: left">* <span style="color: #0000ff">SELECT</span></p>
<p style="text-align: left"><span style="color: #0000ff">FROM </span>Sales.SalesOrderDetail</p>
<p style="text-align: left"><span style="color: #0000ff">WHERE </span>rowguid = @rowguid</p>
<p style="text-align: right">מחר, הטבלה תעבור שינוי ועמודת RowGuid תימחק מן הטבלה. מי שמחק את הטבלה בטוח שלא צריך לעשות שום שינוי ב- SQL משום שהוא שולף נתונים בעזרת * <span style="color: #0000ff">SELECT</span>. אבל משום שהסינון נעשה על עמודה שלא קיימת עוד, נקבל הודעת שגיאה, ואם אין ניטור מסודר של הודעות השגיאה, אז נקבל הודעת שגיאה עלומה, ועכשיו נצטרך להפוך עולמות עד אשר נגלה את הבעיה האמיתית.</p>
<p style="text-align: right">לסיכום, * <span style="color: #0000ff">SELECT </span>נוח לשימוש ויעיל כל עוד לא משתמשים בו באופן קבוע בסביבת Production. בסביבה זו, יש לשאוף למצב שלא יהיה כלל שימוש ב * <span style="color: #0000ff">SELECT</span>. אם וכאשר נגיע למצב שבו אין שימוש ב * <span style="color: #0000ff">SELECT</span>, אנו נרוויח מכך מהרבה בחינות כפי שהוסבר בפוסט זה,</p>
<p style="text-align: right">מקווה שנהניתם לקרוא,</p>
<p style="text-align: right">חקיקת יוסי</p>
</div>]]></content:encoded>			<wfw:commentRss>http://www.madeira.co.il/select/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>&#8235;NOLOCK&#8236;</title>		<link>http://www.madeira.co.il/nolock/</link>
		<comments>http://www.madeira.co.il/nolock/#comments</comments>
		<pubDate>Tue, 17 Jan 2012 00:15:08 +0000</pubDate>
		<dc:creator>&#8235;יוסי חקיקת&#8236;</dc:creator>				<category><![CDATA[כללי]]></category>

		<guid isPermaLink="false">http://www.madeira.co.il/?p=3719</guid>
		<description><![CDATA[&#8235;השימוש ב- NOLCK הפך בארגונים רבים להרגל. לטעמי זה הרגל מגונה. NOLOCK אכן תורם לביצועי המערכת ופותר כליל בעיות הקשורות לנעילות, אך לעיתים הוא יכול לגבות מחיר יקר על השימוש בו. לקבלת מידע מקיף כנסו למאמר....&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p><img src='http://www.madeira.co.il/wp-content/plugins/simple-post-thumbnails/timthumb.php?src=/wp-content/thumbnails/3719.png&amp;w=214&amp;h=129&amp;zc=1&amp;ft=jpg' alt='post thumbnail' /></p>
<p>היו הייתה עיר בשם חלם. חכמי העיר נתקלו באתגר לא פשוט, באחד הגשרים המרכזיים בעיר נפער חור, ורבים מתושבי העיר נפלו מן הגשר ונפצעו. נתכנסו כל חכמי העיר לטכס עצה, אחד מן החכמים שמע על פתרון שיושם בעיר השכנה, וחשב לתומו להעתיק אותו לעיר חלם. הפתרון היה הקמת בית חולים לטיפול בפצועיי הנפילות מהגשר. הדילמה עכשיו הייתה היכן למקם את בית החולים, חשבו וחשבו והגיעו למסקנה שיש למקם את בית החולים בדיוק מתחת לבור שיש בגשר, ככה החולים ייפלו ישר על גג בית החולים ויובהלו לקבלת טיפול רפואי. וכך יצא שהפתרון המזהיר של חכמי העיר למעשה לא הביא לשיפור המצב, ואף גרם להרעה במצב.</p>
<p>הסיפור הנ&quot;ל ממחיש לטעמי בצורה טובה למדיי את כל הקשור לשימוש ב- Locking Hint הנקרא: NOLOCK. ישנה בעיה, בד&quot;כ קשורה לנעילות, ומצד שני ישנו פתרון (NOLOCK) אבל במקרים לא מעטים זה לא הפתרון האמיתי לבעיה אלא פשוט הפתרון הקל. בארגונים רבים ישנו נוהל או מנהג להוסיף לכל שאילתה NOLOCK, בצורה אוטומטית בלי שום קשר לתוכן השליפה וללא מתן תשומת לב לשאלה החשובה כל כך, האם המידע שאני שולף הוא עדכני, תקף ולא עבר שום שינוי בזמן שליפתו! בד&quot;כ הסיבה לשימוש מאסיבי ב- NOLOCK היא זהה במרבית הארגונים, בשלב מסוים, הייתה בעיה של נעילות במערכת שגרמו לעיכובים וכמובן פגעו ישירות בביצועי המערכת, ואז מישהו עלה על הפתרון האולטימטיבי, גם אין נעילות וגם משפרים ביצועים תענוג נכון?? מצטער לקלקל לכם, אבל ממש לא!</p>
<p><span style="text-decoration: underline">ישנן מספר נקודות בסיסיות שעלינו להבין בנוגע לשימוש ב</span><span style="text-decoration: underline">-</span><span style="text-decoration: underline"> </span><span style="text-decoration: underline">NOLOCK</span><span style="text-decoration: underline">:</span></p>
<p>1. <strong>Allow Dirty Reads</strong>- כאשר מריצים פקודת SELECT עם NOLOCK המשמעות היא שאין שום השפעה לנעילות אחרות, כלומר יכול בהחלט להיווצר מצב שאנו קוראים שורות שבינתיים עשו עליהן ROLLBACK או מצד שני שורות שעדיין לא קיבלו COMMIT. (הערה: NOLOCK עובד בדיוק כמו Read Uncommitted, רק ש-Read Uncommitted מוגדר ברמת ה-Session).</p>
<p>2. <strong>לא גורם לנעילות ולא מתחשב בנעילות</strong>- וזו בעצם הסיבה שהשימוש ב-NOLOCK משפר את ביצועי המערכת. מחד גיסא הוא איננו מחזיק שום נעילה בעצמו. ומאידך גיסא, הוא איננו מכבד/מתחשב בשום נעילה אפילו לא בנעילה החזקה ביותר<span style="color: #ff0000"> <a href="http://msdn.microsoft.com/en-us/library/ms175519.aspx" target="_blank"><span style="color: #0000ff">Exclusive Lock</span></a></span>.</p>
<p>3. <strong>רשומות כפולות או היעדר רשומות</strong> &#8211; את הנקודה החשובה והמעניינת הזו לימד אותי <a href="http://www.madeira.co.il/author/noambresiz/" target="_blank"><span style="color: #0000ff">נעם ברזיס</span></a>. כאשר מרצים שאילתה שגורמת לפעולת Index Scan, יכול להיווצר שבו השימוש ב- NOLOCK יגרום ל-SQL Server לא להציג רשומה מסוימת או יציג אותה פעמיים (בלי שום קשר ל- Dirty Reads). לדוגמא:</p>
<p>משתמש הריץ את השאילתה הבאה, (הטבלה בעלת מספר גדול של רשומות) לטבלה יש אינדקס על עמודת Price:</p>
<div style="text-align: left"><span style="color: #0000ff">SELECT</span></div>
<div style="text-align: left">ProductName, Price, Orders</div>
<div style="text-align: left"><span style="color: #0000ff">FROM</span></div>
<div style="text-align: left">Table1</div>
<div style="text-align: left"><span style="color: #0000ff">WHERE</span></div>
<div style="text-align: left">Price BETWEEN 10.00 AND 20.00</div>
<p>לאחר 5 שניות ריצה לדוגמא, פעולת  ה- Index Scan הגיעה לערך 15.00 (יש לזכור שהסקירה מתבצעת לפי סדר האינדקס), משתמש אחר ב- Session אחר כמובן, ביצע פעולת INSERT שה- Price הוא 14.00. במצב זה, הרשומה שזה עתה נכנסה, לא תוצג ב- Record Set . משום שפעולת ה- Index Scan דילגה עליו.</p>
<p>אז לפני שאנו מוציאים נוהל חדש בארגון שמחייב להשתמש ב- NOLOCK באופן קבוע, בואו ננסה להבין ממה יכולות להיגרם נעילות רבות (על שלל סוגיהן):</p>
<p>· <strong>שימוש לא יעיל ב- </strong><strong>Transactions</strong><strong>-</strong> <strong>Transactions </strong>צריכות להישמר קצרות ככל הניתן! לשם המחשה, נגיד שיש לנו פרוצדורה ארוכה שבהתחלה מריצים בה פקודת SELECT דיי כבדה, שמכניסה את הנתונים לטבלה זמנית, לאחר מכן, מבצעים חישוב על אותם נתונים, עושים JOIN עם טבלה אחרת ואז בסוף כל זה יש פקודת UPDATE או DELETE. במצב כזה, יש לפתוח את ה- Transaction רק בפקודת ה-UPDATE או ה- DELETE ולא לאורך כל הפרוצדורה ולסגור אותה מיד בסיום הפעולה!</p>
<p>· <strong>תכנון לקוי</strong>- לעיתים הבעיה נעוצה בסדר הלוגי של הפעולות בתהליך מסוים. יש לנתח ולהבין מה קורה בכל שלב, לנסות לעלות על המצבים בהם יש נעילות שונות. ורק לאחר שמבינים היכן ולמה יש נעילות, לקבל החלטות.</p>
<p>· <strong>Foreign Keys</strong> – יכולים לגרום לנעילות במקרים מסוימים אבל נושא לפוסט שלם.</p>
<p><span style="text-decoration: underline">מתי נשתמש ב- </span><span style="text-decoration: underline">NOLOCK</span><span style="text-decoration: underline"> ומתי לא:</span></p>
<p>כלל ברזל- אם המידע שאנו שולפים צריך להיות מדויק ואמין וללא חשש שהוא השתנה בזמן ששלפנו אותו אז לעולם לא נשתמש ב- NOLOCK. לדוגמא, דוחות שקשורים לכספים וחיובים של לקוחות או גביית כסף, לעולם לא נפיק אותם עם NOLOCK (זו רק דוגמא להמחשה ישנם עוד מקרים רבים אחרים).לעומת זאת, לעיתים תכופות מריצים שאילתות שונות כלליות מאד כדי לקבל תמונת מצב ראשונית על מבנה של טבלאות ועל הנתונים שיש בהן, בדיקות כאלו לרוב לא מחייבות שהמידע יהיה עקבי לאותה שנייה שבא קראנו אותו. יתר על כן, לעיתים ישנם דוחות שמטרתם להציג אומדן ולא נתונים מדויקים, גם במקרים כאלו אין חשש להשתמש ב-NOLOCK.</p>
<p>לסיכום, כמו בהרבה תחומים אחרים ב- SQL Server אנחנו במצב מתמיד של שמיכה קצרה. שמתם NOLOCK הרווחתם ביצועים אבל להבין שיש מחיר לכך, אין ארוחות חינם, נכון, הרווחנו ביצועים, אבל הפסדנו דבר חשוב לא פחות והוא עקביות ואמינות המידע. אז בפעם הבאה שאתם מוסיפים NOLOCK, תעצרו לשנייה ותחשבו על ההשלכות לחיוב ושלילה ותקבלו החלטה מושכלת ומתוך מודעות.</p>
<p>חקיקת יוסי</p>
</div>]]></content:encoded>			<wfw:commentRss>http://www.madeira.co.il/nolock/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>&#8235;Logon Triggers&#8236;</title>		<link>http://www.madeira.co.il/logon-triggers/</link>
		<comments>http://www.madeira.co.il/logon-triggers/#comments</comments>
		<pubDate>Sun, 01 Jan 2012 22:23:30 +0000</pubDate>
		<dc:creator>&#8235;יוסי חקיקת&#8236;</dc:creator>				<category><![CDATA[כללי]]></category>
		<category><![CDATA[Administration]]></category>
		<category><![CDATA[Logon Triggers]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.madeira.co.il/?p=2907</guid>
		<description><![CDATA[&#8235;Logon Triggers שהוצגו החל מ- SQL Server 2005, טומנים בחובם יכולות לא מבוטלות כגון מעקב אחר מספר המשתמשים או אפילו החיבורים אל Instance מסוים, אך לא הכל ורוד לגבי Logon Triggers שימוש לא מושכל עלול לגרור בעיות שונות, רוצים לדעת אילו בעיות ומה היתרונות של Logon Triggers? כנסו למאמר...&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p><img src='http://www.madeira.co.il/wp-content/plugins/simple-post-thumbnails/timthumb.php?src=/wp-content/thumbnails/2907.png&amp;w=214&amp;h=129&amp;zc=1&amp;ft=jpg' alt='post thumbnail' /></p>
<p>בפוסט זה אציג בתחילה בצורה כללית את Logon Triggers, את שימושיו וסוגיו השונים ולאחר מכן אציג מספר קטעי קוד קצרים המיישמים אותו בפועל. ולבסוף אציג את מגרעותיו ומספר טיפים קצרים לשימוש נבון בו.</p>
<p>אז ככה, מגרסת 2005 ומעלה SQL Server הציגו לעולם את הפיצ'ר שנקרא  Logon Triggers שנועד לעזור לנו לשלוט בצורה סינכרונית (הסבר מפורט בהמשך&#8230;) על מספר המשתמשים ברגע נתון ב- Instance מסוים או רק לדעת מי מחובר כרגע. וכמו כן,גם על מספר ה- Sessions  שמריץ כל משתמש. חשוב לציין כי Logon Triggers השונים נכנסים לפעולה אך ורק לאחר השלמת תהליך ההתחברות ל-Instance, אך לפני שהמשתמש פתח Session חדש מול SQL Serve.</p>
<p><strong>איך </strong><strong>Logon Triggers</strong><strong> פועלים?</strong></p>
<p>השינוי המשמעותי ש- Logon Triggers מקנים לנו המשתמשים הוא בעצם ניטור ושליטה סינכרוניים על תהליך יצירת Sessions. אם תרצו, תוכלו לנטר יצירה של Sessions  בעזרת Trace Event שנקרא: AUDIT_LOGIN. ממש כמו Logon Triggers, הוא מופעל בכל פעם שנוצר Session  חדש במערכת אך לפני תחילתו בפועל(כמובן לאחר תהליך ה- Authentication). הבעיה היא, שלא ניתן לנקוט כל פעולה בעזרת ה- Trace Event בתגובה! ופה בעצם טמון היתרון הגדול של Logon Triggers, הם, בניגוד ל- Trace מאפשרים לנו לפעול בתגובה לאירוע של יצירת Session לפני תחילתו בפועל!! קרי, יכולת לשלוט על מספר המשתמשים וה- Sessions בצורה סינכרונית.</p>
<p><span style="font-weight: bold">דוגמא מספר 1: Logon Trigger for all connections</span></p>
<p>עיינו בקוד הבא:</p>
<div class="csharpcode">
<pre style="text-align: left">
<div><span style="color: #0000ff">CREATE TRIGGER</span> MonitoringAllConnections</div>
<div><span style="color: #0000ff">ON</span> <span style="color: #808080">ALL </span><span style="color: #0000ff">SERVER</span></div>
<div><span style="color: #0000ff">AFTER</span> LOGON</div>
<div><span style="color: #0000ff">AS</span></div>
<div><span style="color: #0000ff">BEGIN</span></div>
<div><span style="color: #0000ff"><span style="color: #888888">+</span> <span style="color: #ff0000">'</span>PRINT</span> <span style="color: #ff00ff">SUSER_SNAME</span><span style="color: #808080">() +</span> <span style="color: #ff0000">'</span> <span style="color: #ff0000">Just logged to</span></div>
<div><span style="color: #ff00ff"><span style="color: #888888">+ </span>'UPPER</span><span style="color: #808080">(</span><span style="color: #ff00ff">LTRIM(@@SERVERNAME</span><span style="color: #808080">))+</span> <span style="color: #ff0000">' SQL Server at</span></div>
<div><span style="color: #ff00ff"> <span style="color: #888888">+ </span>':LTRIM</span><span style="color: #808080">(</span><span style="color: #ff00ff">GETDATE</span><span style="color: #808080">()) +</span> <span style="color: #ff0000">' With</span></div>
<div><span style="color: #ff00ff"><span style="color: #888888">()</span>APP_NAME</span></div>
<div><span style="color: #0000ff">END</span></div>
<div><span style="color: #0000ff">GO</span></div>
</pre>
</div>
<p>.Trigger זה מבצע פעולה פשוטה מאד, כל פעם שנוצר חיבור ל- Instance, ולא משנה ע&quot;י מי, מייד תכתב ב- SQL Error Log שורה כזו:</p>
<p><a href="http://www.madeira.co.il/wp-content/uploads/2012/01/LogonErrorLogRow3.png" rel="wp-prettyPhoto[g2907]"><img style="padding-left: 0px;padding-right: 0px;padding-top: 0px;border: 0px" src="http://www.madeira.co.il/wp-content/uploads/2012/01/LogonErrorLogRow_thumb3.png" border="0" alt="LogonErrorLogRow" width="454" height="33" /></a></p>
<p>פקודה זו, טובה לבקרה כללית, אם כי לדעתי ,לא חייבים להשתמש ב Trigger עבורה ניתן להיעזר בDMV שונים.</p>
<p><strong>הערה חשובה ביותר:</strong> במקרה מסוים ניסיתי לשלב בין ה- Logon trigger שבדוגמא זו לבין פקודת INSERT. הכנתי טבלה שמטרתה הייתה לשמור נתונים שונים אודות ההתחברויות (לדוגמא: SYSTEM_USER, USER,APP_NAME(),@@SPID,GETDATE()),התנתקתי מה- Instance ואז להפתעתי הרבה לא הצלחתי להתחבר שוב! (למזלי הרב, צי'קו דרורי (יועץ ב- Madeira), העביר הרצאה מעולה על DAC והצלחתי להתחבר בעזרת <a href="http://msdn.microsoft.com/en-us/library/ms189595.aspx" target="_blank"><span style="color: #0000ff">DAC</span></a> ולמחוק את ה- Trigger ,ניתן להיעזר ב-sys.server_triggers לאיתור ה-Triggers). ואז לאחר חיפוש ב- BOL, הבנתי שאין באפשרות Logon Trigger להחזיר Results Sets. ולפי דעתי זו הסיבה שפעולות ה- INSERT נכשלה וגרוע מכך, אף מנעה ממני להתחבר שוב ל- Instanc.</p>
<p><strong>דוגמא מספר 2: </strong><strong>Logon with restricted number of Sessions per Login</strong></p>
<div class="csharpcode">
<pre style="text-align: left">
<div><span style="color: #0000ff">CREATE TRIGGER</span> LogonTriggerWithConnectionLimit</div>
<div><span style="color: #0000ff"><span style="color: #ff0000">'</span>ON</span> <span style="color: #808080">ALL</span> <span style="color: #0000ff">SERVER WITH EXECUTE AS</span> <span style="color: #ff0000">'</span><span style="color: #ff0000">S</span><span style="color: #ff0000">a</span></div>
<div><span style="color: #0000ff">FOR</span> LOGON</div>
<div><span style="color: #0000ff">AS</span></div>
<div><span style="color: #0000ff">BEGIN</span></div>
<div><span style="color: #0000ff"><span style="color: #ff0000">'</span>IF</span> <span style="color: #ff00ff">ORIGINAL_LOGIN</span><span style="color: #808080">()=</span> <span style="color: #ff0000">'Sa</span></div>
<div><span style="color: #808080">AND</span></div>
<div><span style="color: #808080">)</span></div>
<div><span style="color: #0000ff">SELECT    </span></div>
<div><span style="color: #808080"> (*)</span><span style="color: #ff00ff">COUNT       </span></div>
<div><span style="color: #0000ff">FROM    </span></div>
<div><span style="color: #008000">SYS.DM_EXEC_SESSIONS      </span></div>
<div><span style="color: #0000ff">WHERE    </span></div>
<div>is_user_process <span style="color: #808080">=</span> 1 <span style="color: #008000">-- 1 = User Session || 0 = System Session     </span></div>
<div><span style="color: #808080">AND       </span></div>
<div><span style="color: #ff0000"><span style="color: #888888">5 &lt;</span></span><span style="color: #ff0000"> <span style="color: #888888">(</span> '</span>original_login_name <span style="color: #808080">=</span> <span style="color: #ff0000">'Sa    </span></div>
<div><span style="color: #008000">Allow this user to open only 5 query windows --</span></div>
<div><span style="color: #0000ff"><span style="color: #808080">;</span>ROLLBACK</span></div>
<div><span style="color: #0000ff"><span style="color: #808080">;</span>END</span></div>
</pre>
</div>
<p>במקרה זה באה לידי ביטוי אחת מיכולותיו הייחודיות והמשמעותיות של Logon Triggers. בדוגמא זו, בחרתי להגביל את מספר ה- Sessions של Login בשם sa לחמישה בלבד! כלומר, הוא יוכל לפתוח חמישה חלונות Query שונים, אך אם הוא ינסה לפתוח את השישי הוא יתקל בהודעה הבאה:</p>
<p><a href="http://www.madeira.co.il/wp-content/uploads/2012/01/SaError.png" rel="wp-prettyPhoto[g2907]"><img style="padding-left: 0px;padding-right: 0px;padding-top: 0px;border: 0px" src="http://www.madeira.co.il/wp-content/uploads/2012/01/SaError_thumb.png" border="0" alt="SaError" width="353" height="107" /></a></p>
<p>ניתן בהחלט לשקול שילוב של סינון לפי שעות העומס של המערכת, ולהחליט, שבזמנים בהם ידוע שיש עומס על המערכת, תיושם בפעול הגבלה מסוג זה.</p>
<p><strong>דוגמא מספר 3: מחיקת </strong><strong>Logon Trigger</strong><strong>- </strong></p>
<p>על פניו נראה שאם נריץ את הפקודה הבאה: DROP TRIGGER &lt;Trigger Name&gt; אזי ה- Trigger ימחק. אז זהו שלא&#8230;.. הרצה של הפקודה הבאה תביא להודעת השגיאה הבאה:</p>
<p><a href="http://www.madeira.co.il/wp-content/uploads/2012/01/DropError.png" rel="wp-prettyPhoto[g2907]"><img style="padding-left: 0px;padding-right: 0px;padding-top: 0px;border: 0px" src="http://www.madeira.co.il/wp-content/uploads/2012/01/DropError_thumb.png" border="0" alt="DropError" width="401" height="64" /></a></p>
<p>על מנת למחוק Logon Trigger חייבים להוסיף את השורה הבאה ON ALL SERVER. הפקודה המלאה היא:</p>
<p style="direction: ltr">DROP TRIGGER &lt;Trigger Name&gt; ON ALL SERVER</p>
<p>מכיוון שה- Logon Trigger הוגדר ברמת השרת, יש גם לציין זאת בעת המחיקה.</p>
<p><strong>בקרה וניטור:</strong></p>
<p>ניתן להיעזר ב- DMV הבא- sys.server_triggers, על מנת לקבל רשימה של כל ה- Triggers ברמת Instance, ביניהם ניתן למצוא כמובן את ה- Logon Triggers שהוגדרו.</p>
<p><strong>חסרונות</strong>:</p>
<p>· מנפח את SQL Server Error Log- במידה ומפעילים את ה-LogonTrigger שבדוגמא הראשונה, אזי כל התחברות ל- SQL Server תירשם Error Log, כולל התחברויות של SQL Agent או Reporting Services וכו'. על מנת למנוע מצב זה, יש לבצע סינון חכם של אילו חיבורים אנו מעוניינים לנטר ואילו לא. בדוגמא השנייה, הבעיה עדיין קיימת משום שכל פעם שDBA או מפתח ינסו לפתוח את חלון ה- Query השישי הם יקבלו הודעת שגיאה שאף היא תרשם אל ה- Error Log.</p>
<p>· שימוש לבצע סינון חכם פר משתמשים ולא פר תהליכים שרצים- יש הרבה תהליכי מערכת שרצים ברקע, אין שום שסיבה לפי דעתי שה- Logon Triggers יאכפו אותם.</p>
<p>· במקרים של שימוש לא נכון, ה- Logon Trigger עלול למנוע גישה ל- SQL Server- כפי שהוסבר, במקרים בהם נרצה להריץ פקודת SELECT בתוך ה- Trigger, בכניסה הבאה שלנו, לא נוכל להיכנס אלא באמצעות ה- DAC.</p>
<p>לסיכום, LogonTriggers עוזרים לנו לשלוט על מספר המשתמשים, על מספר התהליכים שהם מריצים, אך אליה וקוץ בה, יש לשים לב לחסרונות הלא מבוטלים שלהם. מקווה שעזרתי, אשמח לשמוע את תגובותיכם,</p>
<p>חקיקת יוסי</p>
</div>]]></content:encoded>			<wfw:commentRss>http://www.madeira.co.il/logon-triggers/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

